@tangram.gl/tangram-renderer 0.0.0-stage → 0.0.1

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 (321) hide show
  1. package/README.md +60 -2
  2. package/dist/core.js +36923 -0
  3. package/dist/core.js.map +6 -0
  4. package/dist/index.js +32 -0
  5. package/dist/loaders-gl-worker.js +82 -0
  6. package/dist/loaders-gl-worker.js.map +6 -0
  7. package/dist/map-logic.js +2 -0
  8. package/dist/map-logic.js.map +6 -0
  9. package/dist/projected-basemaps-worker.js +3 -0
  10. package/dist/projected-basemaps-worker.js.map +6 -0
  11. package/dist/shader-modules.js +141 -0
  12. package/dist/shader-modules.js.map +6 -0
  13. package/dist/style-schema.js +126 -0
  14. package/dist/style-schema.js.map +6 -0
  15. package/dist/tangram-style.schema.json +882 -0
  16. package/dist/tangram.debug.mjs +37139 -0
  17. package/dist/tangram.debug.mjs.map +6 -0
  18. package/dist/tangram.min.mjs +4950 -0
  19. package/dist/types/builders/earcut.d.ts +15 -0
  20. package/dist/types/core.d.ts +29 -0
  21. package/dist/types/gl/constants.d.ts +2 -0
  22. package/dist/types/gl/globe_mesh.d.ts +48 -0
  23. package/dist/types/gl/glsl.d.ts +17 -0
  24. package/dist/types/gl/vertex-constants.d.ts +4 -0
  25. package/dist/types/gl/vertex-types.d.ts +34 -0
  26. package/dist/types/gl/vertex_data.d.ts +32 -0
  27. package/dist/types/gl/vertex_elements.d.ts +8 -0
  28. package/dist/types/gl/vertex_layout.d.ts +32 -0
  29. package/dist/types/glsl.d.ts +14 -0
  30. package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
  31. package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
  32. package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
  33. package/dist/types/index.d.ts +155 -0
  34. package/dist/types/lights/light-definitions.d.ts +121 -0
  35. package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
  36. package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
  37. package/dist/types/map-logic/globe-terrain.d.ts +54 -0
  38. package/dist/types/map-logic/index.d.ts +33 -0
  39. package/dist/types/map-logic/label-identity.d.ts +22 -0
  40. package/dist/types/map-logic/label-placement.d.ts +32 -0
  41. package/dist/types/map-logic/screen-bounds.d.ts +15 -0
  42. package/dist/types/map-logic/terrain-data.d.ts +55 -0
  43. package/dist/types/map-logic/terrain-error.d.ts +51 -0
  44. package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
  45. package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
  46. package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
  47. package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
  48. package/dist/types/map-logic/terrain-query.d.ts +33 -0
  49. package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
  50. package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
  51. package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
  52. package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
  53. package/dist/types/map-logic/tile-residency.d.ts +17 -0
  54. package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
  55. package/dist/types/procedures/js-yaml.d.ts +15 -0
  56. package/dist/types/procedures/mesh-projector.d.ts +107 -0
  57. package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
  58. package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
  59. package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
  60. package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
  61. package/dist/types/procedures/terrain-draping.d.ts +165 -0
  62. package/dist/types/procedures/terrain-globe.d.ts +6 -0
  63. package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
  64. package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
  65. package/dist/types/procedures/web-mercator-math.d.ts +4 -0
  66. package/dist/types/scene/globals.d.ts +11 -0
  67. package/dist/types/scene/ground_footprint.d.ts +16 -0
  68. package/dist/types/scene/host_frame.d.ts +54 -0
  69. package/dist/types/scene/projection_math.d.ts +52 -0
  70. package/dist/types/scene/scene-resource-types.d.ts +177 -0
  71. package/dist/types/scene/scene_bundle.d.ts +69 -0
  72. package/dist/types/scene/visibility_adapter.d.ts +106 -0
  73. package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
  74. package/dist/types/selection/terrain_surface.d.ts +149 -0
  75. package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
  76. package/dist/types/shader-modules/height-decode.d.ts +13 -0
  77. package/dist/types/shader-modules/hillshade.d.ts +13 -0
  78. package/dist/types/shader-modules/index.d.ts +6 -0
  79. package/dist/types/shader-modules/planar.d.ts +12 -0
  80. package/dist/types/shader-modules/sphere-map.d.ts +13 -0
  81. package/dist/types/shader-modules/triplanar.d.ts +15 -0
  82. package/dist/types/sources/decoded_tile_store.d.ts +95 -0
  83. package/dist/types/sources/tile_source_metadata.d.ts +32 -0
  84. package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
  85. package/dist/types/tile/tile_id.d.ts +37 -0
  86. package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
  87. package/dist/types/types.d.ts +293 -0
  88. package/dist/types/utils/geo.d.ts +57 -0
  89. package/dist/types/utils/hash.d.ts +1 -0
  90. package/dist/types/utils/log.d.ts +27 -0
  91. package/dist/types/utils/props.d.ts +6 -0
  92. package/dist/types/utils/subscribe.d.ts +10 -0
  93. package/dist/types/utils/thread.d.ts +6 -0
  94. package/dist/types/utils/urls.d.ts +26 -0
  95. package/dist/types/utils/utils.d.ts +26 -0
  96. package/dist/types/utils/version.d.ts +2 -0
  97. package/dist/types/utils/worker-types.d.ts +68 -0
  98. package/dist/types/utils/worker_broker.d.ts +3 -0
  99. package/package.json +103 -3
  100. package/src/builders/common.ts +41 -0
  101. package/src/builders/earcut.d.ts +15 -0
  102. package/src/builders/geometry-types.ts +60 -0
  103. package/src/builders/points.ts +115 -0
  104. package/src/builders/polygons.ts +225 -0
  105. package/src/builders/polylines.ts +682 -0
  106. package/src/builders/wireframe.ts +31 -0
  107. package/src/core.d.ts +29 -0
  108. package/src/core.ts +33 -0
  109. package/src/experimental/loaders-gl-worker.ts +19 -0
  110. package/src/experimental/projected-basemaps-worker.ts +13 -0
  111. package/src/experimental/projected-mesh-cache.ts +137 -0
  112. package/src/experimental/projected-mesh-domain.ts +110 -0
  113. package/src/experimental/projected-mesh-refinement.ts +193 -0
  114. package/src/experimental/projected-mesh.ts +399 -0
  115. package/src/experimental/projected-normal.ts +26 -0
  116. package/src/experimental/projected-symbol-mesh.ts +74 -0
  117. package/src/gl/constants.ts +18 -0
  118. package/src/gl/context.ts +103 -0
  119. package/src/gl/extensions.ts +30 -0
  120. package/src/gl/globe_mesh.ts +285 -0
  121. package/src/gl/glsl.ts +257 -0
  122. package/src/gl/mesh-types.ts +56 -0
  123. package/src/gl/render_state.ts +111 -0
  124. package/src/gl/shader_program.ts +1310 -0
  125. package/src/gl/texture.ts +814 -0
  126. package/src/gl/uniform_buffer.ts +340 -0
  127. package/src/gl/vao.ts +154 -0
  128. package/src/gl/vbo_mesh.ts +349 -0
  129. package/src/gl/vertex-constants.ts +19 -0
  130. package/src/gl/vertex-types.ts +35 -0
  131. package/src/gl/vertex_data.ts +126 -0
  132. package/src/gl/vertex_elements.ts +54 -0
  133. package/src/gl/vertex_layout.ts +241 -0
  134. package/src/glsl.d.ts +14 -0
  135. package/src/gpu/luma_device_renderer.ts +579 -0
  136. package/src/gpu/pixel_readback.ts +51 -0
  137. package/src/gpu/resource_lifecycle.ts +32 -0
  138. package/src/gpu/tangram_gpu_backend.ts +195 -0
  139. package/src/index.d.ts +155 -0
  140. package/src/index.ts +105 -0
  141. package/src/labels/collision-types.ts +94 -0
  142. package/src/labels/collision.ts +273 -0
  143. package/src/labels/collision_grid.ts +61 -0
  144. package/src/labels/intersect.ts +30 -0
  145. package/src/labels/label-types.ts +91 -0
  146. package/src/labels/label.ts +207 -0
  147. package/src/labels/label_line.ts +801 -0
  148. package/src/labels/label_point.ts +131 -0
  149. package/src/labels/main-pass-types.ts +73 -0
  150. package/src/labels/main_pass.ts +221 -0
  151. package/src/labels/point_anchor.ts +100 -0
  152. package/src/labels/point_placement.ts +150 -0
  153. package/src/labels/projected-pass.ts +259 -0
  154. package/src/labels/repeat_group.ts +72 -0
  155. package/src/lights/ambient_light.glsl +18 -0
  156. package/src/lights/directional_light.glsl +39 -0
  157. package/src/lights/geographic-lights.ts +21 -0
  158. package/src/lights/light-definitions.ts +285 -0
  159. package/src/lights/light.ts +590 -0
  160. package/src/lights/lighting-uniforms.ts +80 -0
  161. package/src/lights/lighting-wgsl.ts +116 -0
  162. package/src/lights/material.glsl +237 -0
  163. package/src/lights/material.ts +145 -0
  164. package/src/lights/native-falloff.ts +37 -0
  165. package/src/lights/point_light.glsl +96 -0
  166. package/src/lights/spot_light.glsl +111 -0
  167. package/src/map-logic/draped-terrain-bounds.ts +71 -0
  168. package/src/map-logic/globe-terrain-preparation.ts +217 -0
  169. package/src/map-logic/globe-terrain.ts +296 -0
  170. package/src/map-logic/index.ts +37 -0
  171. package/src/map-logic/label-identity.ts +36 -0
  172. package/src/map-logic/label-placement.ts +117 -0
  173. package/src/map-logic/screen-bounds.ts +34 -0
  174. package/src/map-logic/terrain-data.ts +107 -0
  175. package/src/map-logic/terrain-error.ts +134 -0
  176. package/src/map-logic/terrain-ground-topology.ts +164 -0
  177. package/src/map-logic/terrain-height-field.ts +254 -0
  178. package/src/map-logic/terrain-navigation.ts +50 -0
  179. package/src/map-logic/terrain-neighborhood.ts +43 -0
  180. package/src/map-logic/terrain-query.ts +51 -0
  181. package/src/map-logic/terrain-resource-budget.ts +124 -0
  182. package/src/map-logic/terrain-transition-topology.ts +164 -0
  183. package/src/map-logic/tile-build-queue.ts +110 -0
  184. package/src/map-logic/tile-cache-policy.ts +89 -0
  185. package/src/map-logic/tile-residency.ts +50 -0
  186. package/src/map-logic/triangle-query-index.ts +265 -0
  187. package/src/procedures/js-yaml.d.ts +15 -0
  188. package/src/procedures/mesh-projector.ts +191 -0
  189. package/src/procedures/mlt-loaders.ts +55 -0
  190. package/src/procedures/mvt-dependencies.d.ts +20 -0
  191. package/src/procedures/mvt-legacy.ts +150 -0
  192. package/src/procedures/mvt-loaders.ts +53 -0
  193. package/src/procedures/mvt-parser.ts +48 -0
  194. package/src/procedures/mvt-properties.ts +36 -0
  195. package/src/procedures/mvt-tile-provider.ts +72 -0
  196. package/src/procedures/pmtiles-loader.ts +75 -0
  197. package/src/procedures/projected-coordinate-transform.ts +79 -0
  198. package/src/procedures/projection-batch-executor.ts +140 -0
  199. package/src/procedures/scene-yaml-legacy.ts +16 -0
  200. package/src/procedures/scene-yaml-loaders.ts +10 -0
  201. package/src/procedures/terrain-draping.ts +713 -0
  202. package/src/procedures/terrain-globe.ts +32 -0
  203. package/src/procedures/terrain-styled-topology.ts +184 -0
  204. package/src/procedures/web-mercator-legacy.ts +24 -0
  205. package/src/procedures/web-mercator-math.ts +50 -0
  206. package/src/scene/camera.ts +298 -0
  207. package/src/scene/camera_base.ts +116 -0
  208. package/src/scene/classic_scene.ts +20 -0
  209. package/src/scene/external_camera.ts +101 -0
  210. package/src/scene/globals.ts +120 -0
  211. package/src/scene/ground_footprint.ts +139 -0
  212. package/src/scene/host_frame.ts +326 -0
  213. package/src/scene/projected_tile_lod.ts +125 -0
  214. package/src/scene/projection_math.ts +142 -0
  215. package/src/scene/projection_shaders.ts +183 -0
  216. package/src/scene/renderer.ts +516 -0
  217. package/src/scene/scene-resource-types.ts +174 -0
  218. package/src/scene/scene.ts +2378 -0
  219. package/src/scene/scene_bundle.ts +304 -0
  220. package/src/scene/scene_debug.ts +129 -0
  221. package/src/scene/scene_loader.ts +402 -0
  222. package/src/scene/scene_worker.ts +528 -0
  223. package/src/scene/view.ts +683 -0
  224. package/src/scene/visibility_adapter.ts +319 -0
  225. package/src/scene/worker_url.ts +15 -0
  226. package/src/selection/draped-terrain-surface.ts +377 -0
  227. package/src/selection/selection-types.ts +79 -0
  228. package/src/selection/selection.ts +542 -0
  229. package/src/selection/selection_fragment.glsl +18 -0
  230. package/src/selection/selection_globals.glsl +9 -0
  231. package/src/selection/selection_pixels.ts +59 -0
  232. package/src/selection/selection_vertex.glsl +15 -0
  233. package/src/selection/terrain_surface.ts +298 -0
  234. package/src/shader-modules/globe-horizon.ts +52 -0
  235. package/src/shader-modules/height-decode.ts +41 -0
  236. package/src/shader-modules/hillshade.ts +70 -0
  237. package/src/shader-modules/index.ts +10 -0
  238. package/src/shader-modules/planar.ts +24 -0
  239. package/src/shader-modules/sphere-map.ts +38 -0
  240. package/src/shader-modules/triplanar.ts +45 -0
  241. package/src/sources/aligned_tile_source.ts +122 -0
  242. package/src/sources/data_source.ts +655 -0
  243. package/src/sources/decoded_tile_store.ts +245 -0
  244. package/src/sources/geojson.ts +300 -0
  245. package/src/sources/mvt.ts +247 -0
  246. package/src/sources/raster.ts +341 -0
  247. package/src/sources/shared_tile_source_adapter.ts +117 -0
  248. package/src/sources/sources.ts +10 -0
  249. package/src/sources/tile_source_adapter.ts +84 -0
  250. package/src/sources/tile_source_metadata.ts +65 -0
  251. package/src/sources/tile_source_state.ts +112 -0
  252. package/src/sources/topojson.ts +90 -0
  253. package/src/styles/feature_annotations.ts +16 -0
  254. package/src/styles/filter.ts +190 -0
  255. package/src/styles/geometry-style-types.ts +209 -0
  256. package/src/styles/globe_visibility_wgsl.ts +22 -0
  257. package/src/styles/layer-types.ts +45 -0
  258. package/src/styles/layer.ts +586 -0
  259. package/src/styles/lines/dasharray.ts +49 -0
  260. package/src/styles/lines/lines.ts +707 -0
  261. package/src/styles/lines/lines_wgsl.ts +224 -0
  262. package/src/styles/points/point-runtime-types.ts +125 -0
  263. package/src/styles/points/points.ts +1079 -0
  264. package/src/styles/points/points_fragment.glsl +126 -0
  265. package/src/styles/points/points_vertex.glsl +230 -0
  266. package/src/styles/points/points_wgsl.ts +189 -0
  267. package/src/styles/polygons/polygons.ts +268 -0
  268. package/src/styles/polygons/polygons_fragment.glsl +173 -0
  269. package/src/styles/polygons/polygons_vertex.glsl +213 -0
  270. package/src/styles/polygons/polygons_wgsl.ts +127 -0
  271. package/src/styles/property-types.ts +125 -0
  272. package/src/styles/raster/raster.ts +33 -0
  273. package/src/styles/raster/raster_globals.glsl +46 -0
  274. package/src/styles/style-mixing-types.ts +101 -0
  275. package/src/styles/style-runtime-types.ts +220 -0
  276. package/src/styles/style-schema.ts +133 -0
  277. package/src/styles/style.ts +1033 -0
  278. package/src/styles/style_globals.glsl +69 -0
  279. package/src/styles/style_manager.ts +464 -0
  280. package/src/styles/style_parser.ts +620 -0
  281. package/src/styles/text/font_manager.ts +180 -0
  282. package/src/styles/text/fontfaceobserver.d.ts +10 -0
  283. package/src/styles/text/text-types.ts +220 -0
  284. package/src/styles/text/text.ts +378 -0
  285. package/src/styles/text/text_canvas.ts +773 -0
  286. package/src/styles/text/text_labels.ts +436 -0
  287. package/src/styles/text/text_segments.ts +142 -0
  288. package/src/styles/text/text_settings.ts +228 -0
  289. package/src/styles/text/text_wgsl.ts +159 -0
  290. package/src/styles/text/text_wrap.ts +194 -0
  291. package/src/tile/globe_tile_preload.ts +40 -0
  292. package/src/tile/tangram_tileset_2d.ts +108 -0
  293. package/src/tile/tile-build-types.ts +155 -0
  294. package/src/tile/tile.ts +807 -0
  295. package/src/tile/tile_id.ts +172 -0
  296. package/src/tile/tile_manager.ts +889 -0
  297. package/src/tile/tile_pyramid.ts +119 -0
  298. package/src/tile/tile_resource_cache.ts +91 -0
  299. package/src/tile/tile_traversal_adapter.ts +132 -0
  300. package/src/types.ts +332 -0
  301. package/src/utils/debounce.ts +17 -0
  302. package/src/utils/debug_settings.ts +43 -0
  303. package/src/utils/errors.ts +12 -0
  304. package/src/utils/functions.ts +95 -0
  305. package/src/utils/geo.ts +364 -0
  306. package/src/utils/hash.ts +14 -0
  307. package/src/utils/log.ts +108 -0
  308. package/src/utils/media_capture.ts +193 -0
  309. package/src/utils/merge.ts +44 -0
  310. package/src/utils/obb.ts +134 -0
  311. package/src/utils/props.ts +43 -0
  312. package/src/utils/slice.ts +14 -0
  313. package/src/utils/subscribe.ts +58 -0
  314. package/src/utils/task.ts +154 -0
  315. package/src/utils/thread.ts +26 -0
  316. package/src/utils/urls.ts +223 -0
  317. package/src/utils/utils.ts +310 -0
  318. package/src/utils/vector.ts +197 -0
  319. package/src/utils/version.ts +8 -0
  320. package/src/utils/worker-types.ts +79 -0
  321. package/src/utils/worker_broker.ts +523 -0
@@ -0,0 +1,193 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ import log from './log';
7
+ import {createObjectURL} from './urls';
8
+ import StyleParser from '../styles/style_parser';
9
+
10
+ export default class MediaCapture {
11
+ canvas: any;
12
+ gl: any;
13
+ screenshot_canvas: HTMLCanvasElement | null;
14
+ screenshot_context: CanvasRenderingContext2D | null;
15
+ queue_screenshot: any;
16
+ video_capture: any;
17
+
18
+ constructor() {
19
+ this.canvas = null;
20
+ this.gl = null;
21
+ this.screenshot_canvas = null;
22
+ this.screenshot_context = null;
23
+ this.queue_screenshot = null;
24
+ this.video_capture = null;
25
+ }
26
+
27
+ setCanvas (canvas: any, gl: any): void {
28
+ this.canvas = canvas;
29
+ this.gl = gl;
30
+ }
31
+
32
+ // Take a screenshot, returns a promise that resolves with the screenshot data when available
33
+ // `background`: optional background color to blend screenshot with
34
+ screenshot ({ background }: {background?: string} = {}): Promise<any> {
35
+ if (this.queue_screenshot != null) {
36
+ return this.queue_screenshot.promise; // only capture one screenshot at a time
37
+ }
38
+
39
+ // Will resolve once rendering is complete and render buffer is captured
40
+ this.queue_screenshot = { background };
41
+ this.queue_screenshot.promise = new Promise((resolve, reject) => {
42
+ this.queue_screenshot.resolve = resolve;
43
+ this.queue_screenshot.reject = reject;
44
+ });
45
+ return this.queue_screenshot.promise;
46
+ }
47
+
48
+ // Called after rendering, captures render buffer and resolves promise with the image data
49
+ completeScreenshot (): void {
50
+ if (this.queue_screenshot != null) {
51
+ // Firefox appears to have an issue where its alpha conversion overflows some channels when
52
+ // the WebGL canvas content is captured. To get around this, we read pixels from the GL buffer
53
+ // directly, then flip and unmulitply the alpha on each pixel to get the desired RGB values.
54
+ // See https://github.com/tangrams/tangram/issues/551
55
+
56
+ // Get raw pixels from GL
57
+ let w = this.canvas.width;
58
+ let h = this.canvas.height;
59
+ let pixels = new Uint8Array(w * h * 4);
60
+ this.gl.readPixels(0, 0, w, h, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pixels);
61
+
62
+ // Optional background to blend with (only RGB, alpha is ignored)
63
+ let background = this.queue_screenshot.background;
64
+ if (background && background !== 'transparent') {
65
+ background = (StyleParser as any).parseColor(background).slice(0, 3).map((c: number) => c * 255) as any;
66
+ }
67
+ else {
68
+ background = null; // skip blend if transparent
69
+ }
70
+
71
+ // Flip Y (GL buffer is upside down)
72
+ let flip = new Uint8ClampedArray(w * h * 4); // canvas requires 'clamped' array type
73
+ for (let y=0; y < h; y++) {
74
+ for (let x=0; x < w; x++) {
75
+ let s = ((h - y - 1) * w + x) * 4; // source offset
76
+ let d = (y * w + x) * 4; // destination offset
77
+ let a = pixels[s + 3]; // unmultiply alpha
78
+ flip[d + 0] = pixels[s + 0] * 255 / a;
79
+ flip[d + 1] = pixels[s + 1] * 255 / a;
80
+ flip[d + 2] = pixels[s + 2] * 255 / a;
81
+ flip[d + 3] = a;
82
+
83
+ if (background) {
84
+ a /= 255;
85
+ flip[d + 0] = (flip[d + 0] * a) + (background[0] * (1 - a));
86
+ flip[d + 1] = (flip[d + 1] * a) + (background[1] * (1 - a));
87
+ flip[d + 2] = (flip[d + 2] * a) + (background[2] * (1 - a));
88
+ flip[d + 3] = 255;
89
+ }
90
+ }
91
+ }
92
+
93
+ // Draw flipped pixels to a canvas
94
+ this.screenshot_canvas = this.screenshot_canvas || document.createElement('canvas');
95
+ let canvas = this.screenshot_canvas;
96
+ canvas.width = w;
97
+ canvas.height = h;
98
+
99
+ this.screenshot_context = this.screenshot_context || canvas.getContext('2d');
100
+ let ctx = this.screenshot_context;
101
+ let image = new ImageData(flip, w, h);
102
+ ctx!.putImageData(image, 0, 0);
103
+
104
+ // Get data URL from canvas and convert to blob
105
+ // Strip host/mimetype/etc., convert base64 to binary without UTF-8 mangling
106
+ // Adapted from: https://gist.github.com/unconed/4370822
107
+ const url = canvas.toDataURL('image/png');
108
+ const data = atob(url.slice(22));
109
+ const buffer = new Uint8Array(data.length);
110
+ for (let i = 0; i < data.length; ++i) {
111
+ buffer[i] = data.charCodeAt(i);
112
+ }
113
+ const blob = new Blob([buffer], { type: 'image/png' });
114
+
115
+ // Resolve with screenshot data
116
+ this.queue_screenshot.resolve({ url, blob, type: 'png' });
117
+ this.queue_screenshot = null;
118
+ }
119
+ }
120
+
121
+ // Starts capturing a video stream from the canvas
122
+ startVideoCapture (): boolean {
123
+ if (typeof window === 'undefined' || typeof window.MediaRecorder !== 'function' || !this.canvas || typeof this.canvas.captureStream !== 'function') {
124
+ log('warn', 'Video capture (Canvas.captureStream and/or MediaRecorder APIs) not supported by browser');
125
+ return false;
126
+ }
127
+ else if (this.video_capture) {
128
+ log('warn', 'Video capture already in progress, call Scene.stopVideoCapture() first');
129
+ return false;
130
+ }
131
+
132
+ // Start a new capture
133
+ try {
134
+ const cap: any = this.video_capture = {};
135
+ cap.chunks = [];
136
+ cap.stream = this.canvas.captureStream();
137
+ cap.options = { mimeType: 'video/webm' }; // TODO: support other format options
138
+ cap.media_recorder = new MediaRecorder(cap.stream, cap.options);
139
+ cap.media_recorder.ondataavailable = (event: any) => {
140
+ if (event.data.size > 0) {
141
+ cap.chunks.push(event.data);
142
+ }
143
+
144
+ // Stopped recording? Create the final capture file blob
145
+ if (cap.resolve) {
146
+ let blob = new Blob(cap.chunks, { type: cap.options.mimeType });
147
+ let url = createObjectURL(blob);
148
+
149
+ // Explicitly remove all stream tracks, and set objects to null
150
+ if (cap.stream) {
151
+ let tracks = cap.stream.getTracks() || [];
152
+ tracks.forEach((track: MediaStreamTrack) => {
153
+ track.stop();
154
+ cap.stream.removeTrack(track);
155
+ });
156
+ }
157
+ cap.stream = null;
158
+ cap.media_recorder = null;
159
+ this.video_capture = null;
160
+
161
+ cap.resolve({ url, blob, type: 'webm' });
162
+ }
163
+ };
164
+ cap.media_recorder.start();
165
+ }
166
+ catch (e) {
167
+ this.video_capture = null;
168
+ log('error', 'Scene video capture failed', e);
169
+ return false;
170
+ }
171
+ return true;
172
+ }
173
+
174
+ // Stops capturing a video stream from the canvas, returns a promise that resolves with the video when available
175
+ stopVideoCapture (): Promise<any> {
176
+ if (!this.video_capture) {
177
+ log('warn', 'No scene video capture in progress, call Scene.startVideoCapture() first');
178
+ return Promise.resolve({});
179
+ }
180
+
181
+ // Promise that will resolve when final stream is available
182
+ this.video_capture.promise = new Promise((resolve, reject) => {
183
+ this.video_capture.resolve = resolve;
184
+ this.video_capture.reject = reject;
185
+ });
186
+
187
+ // Stop recording
188
+ this.video_capture.media_recorder.stop();
189
+
190
+ return this.video_capture.promise;
191
+ }
192
+
193
+ }
@@ -0,0 +1,44 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ // Deep/recursive merge of one or more source objects into a destination object
7
+ type MutableRecord = Record<string, unknown>;
8
+
9
+ function isMergeableObject(value: unknown): value is MutableRecord {
10
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
11
+ }
12
+
13
+ export default function mergeObjects<Destination extends object>(
14
+ destination: Destination,
15
+ ...sources: Array<object | null | undefined>
16
+ ): Destination {
17
+ const destinationRecord = destination as MutableRecord;
18
+
19
+ for (const source of sources) {
20
+ if (!source) {
21
+ continue;
22
+ }
23
+
24
+ for (const key in source) {
25
+ const sourceRecord = source as MutableRecord;
26
+ const value = sourceRecord[key];
27
+
28
+ // Recursively merge the source into the destination if it is a non-null key/value object.
29
+ // Arrays are treated as scalar values; null values overwrite the previous destination value.
30
+ if (isMergeableObject(value)) {
31
+ const destinationValue = destinationRecord[key];
32
+ destinationRecord[key] = isMergeableObject(destinationValue)
33
+ ? mergeObjects(destinationValue, value)
34
+ : mergeObjects({}, value);
35
+ }
36
+ // Undefined source properties are ignored. All other values overwrite the destination.
37
+ else if (value !== undefined) {
38
+ destinationRecord[key] = value;
39
+ }
40
+ }
41
+ }
42
+
43
+ return destination;
44
+ }
@@ -0,0 +1,134 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ import {Vector2} from '@math.gl/core';
7
+ import type {MutableNumericVector, NumericVector} from './vector';
8
+
9
+ type Quad = [number, number, number, number, number, number, number, number];
10
+ type Extent = [number, number, number, number];
11
+
12
+ const ZERO_AXES: MutableNumericVector[] = [[1, 0], [0, 1]];
13
+ const projectionA: MutableNumericVector = [];
14
+ const projectionB: MutableNumericVector = [];
15
+
16
+ /** Two-dimensional oriented bounding box. */
17
+ export default class OBB {
18
+ /** Half-width and half-height. */
19
+ readonly dimension: [number, number];
20
+ /** Rotation angle in radians. */
21
+ angle: number;
22
+ /** Box center. */
23
+ readonly centroid: [number, number];
24
+ /** Flattened corner coordinates. */
25
+ quad!: Quad;
26
+ /** First normalized separating axis. */
27
+ axis_0!: MutableNumericVector;
28
+ /** Second normalized separating axis. */
29
+ axis_1!: MutableNumericVector;
30
+
31
+ constructor(x: number, y: number, angle: number, width: number, height: number) {
32
+ this.dimension = [width / 2, height / 2];
33
+ this.angle = angle;
34
+ this.centroid = [x, y];
35
+ this.update();
36
+ }
37
+
38
+ /** Returns a serializable representation of the box. */
39
+ toJSON(): {x: number; y: number; a: number; w: number; h: number} {
40
+ return {
41
+ x: this.centroid[0],
42
+ y: this.centroid[1],
43
+ a: this.angle,
44
+ w: this.dimension[0],
45
+ h: this.dimension[1]
46
+ };
47
+ }
48
+
49
+ /** Returns the axis-aligned extent containing the box. */
50
+ getExtent(): Extent {
51
+ if (this.angle === 0) {
52
+ return [this.quad[0], this.quad[1], this.quad[4], this.quad[5]];
53
+ }
54
+
55
+ return [
56
+ Math.min(this.quad[0], this.quad[2], this.quad[4], this.quad[6]),
57
+ Math.min(this.quad[1], this.quad[3], this.quad[5], this.quad[7]),
58
+ Math.max(this.quad[0], this.quad[2], this.quad[4], this.quad[6]),
59
+ Math.max(this.quad[1], this.quad[3], this.quad[5], this.quad[7])
60
+ ];
61
+ }
62
+
63
+ /** Recalculates the normalized box axes. */
64
+ updateAxes(): void {
65
+ this.axis_0 = new Vector2([
66
+ this.quad[4] - this.quad[6],
67
+ this.quad[5] - this.quad[7]
68
+ ]).normalize().toArray([]);
69
+ this.axis_1 = new Vector2([
70
+ this.quad[4] - this.quad[2],
71
+ this.quad[5] - this.quad[3]
72
+ ]).normalize().toArray([]);
73
+ }
74
+
75
+ /** Recalculates corners and axes from the current center, dimensions, and angle. */
76
+ update(): void {
77
+ const [centerX, centerY] = this.centroid;
78
+ const [halfWidth, halfHeight] = this.dimension;
79
+
80
+ if (this.angle === 0) {
81
+ this.quad = [
82
+ centerX - halfWidth, centerY - halfHeight,
83
+ centerX + halfWidth, centerY - halfHeight,
84
+ centerX + halfWidth, centerY + halfHeight,
85
+ centerX - halfWidth, centerY + halfHeight
86
+ ];
87
+ this.axis_0 = ZERO_AXES[0];
88
+ this.axis_1 = ZERO_AXES[1];
89
+ return;
90
+ }
91
+
92
+ const widthX = Math.cos(this.angle) * halfWidth;
93
+ const widthY = Math.sin(this.angle) * halfWidth;
94
+ const heightX = -Math.sin(this.angle) * halfHeight;
95
+ const heightY = Math.cos(this.angle) * halfHeight;
96
+ this.quad = [
97
+ centerX - widthX - heightX, centerY - widthY - heightY,
98
+ centerX + widthX - heightX, centerY + widthY - heightY,
99
+ centerX + widthX + heightX, centerY + widthY + heightY,
100
+ centerX - widthX + heightX, centerY - widthY + heightY
101
+ ];
102
+ this.updateAxes();
103
+ }
104
+
105
+ /** Projects a box onto an axis and writes its minimum and maximum values. */
106
+ static projectToAxis(box: OBB, axis: NumericVector, projection: MutableNumericVector): MutableNumericVector {
107
+ const dot0 = box.quad[0] * axis[0] + box.quad[1] * axis[1];
108
+ const dot1 = box.quad[2] * axis[0] + box.quad[3] * axis[1];
109
+ const dot2 = box.quad[4] * axis[0] + box.quad[5] * axis[1];
110
+ const dot3 = box.quad[6] * axis[0] + box.quad[7] * axis[1];
111
+ projection[0] = Math.min(dot0, dot1, dot2, dot3);
112
+ projection[1] = Math.max(dot0, dot1, dot2, dot3);
113
+ return projection;
114
+ }
115
+
116
+ /** Tests two separating axes for overlap. */
117
+ static axisCollide(first: OBB, second: OBB, axis0: NumericVector, axis1: NumericVector): boolean {
118
+ OBB.projectToAxis(first, axis0, projectionA);
119
+ OBB.projectToAxis(second, axis0, projectionB);
120
+ if (projectionB[0] > projectionA[1] || projectionB[1] < projectionA[0]) {
121
+ return false;
122
+ }
123
+
124
+ OBB.projectToAxis(first, axis1, projectionA);
125
+ OBB.projectToAxis(second, axis1, projectionB);
126
+ return !(projectionB[0] > projectionA[1] || projectionB[1] < projectionA[0]);
127
+ }
128
+
129
+ /** Tests whether two oriented boxes intersect. */
130
+ static intersect(first: OBB, second: OBB): boolean {
131
+ return OBB.axisCollide(first, second, first.axis_0, first.axis_1) &&
132
+ OBB.axisCollide(first, second, second.axis_0, second.axis_1);
133
+ }
134
+ }
@@ -0,0 +1,43 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ // Get a value for a nested property with path provided as an array (`a.b.c` => ['a', 'b', 'c'])
7
+ type PropertyTarget = Record<PropertyKey, unknown>;
8
+ export type PropertyPath = readonly PropertyKey[];
9
+
10
+ export function getPropertyPath(object: object, path: PropertyPath): unknown {
11
+ const property = path[path.length - 1];
12
+ return getPropertyPathTarget(object, path)?.[property];
13
+ }
14
+
15
+ // Set a value for a nested property with path provided as an array (`a.b.c` => ['a', 'b', 'c'])
16
+ export function setPropertyPath(object: object, path: PropertyPath, value: unknown): void {
17
+ const property = path[path.length - 1];
18
+ const target = getPropertyPathTarget(object, path);
19
+ if (target) {
20
+ target[property] = value;
21
+ }
22
+ }
23
+
24
+ // Get the immediate parent object for a property path name provided as an array
25
+ // e.g. for a single-depth path, this is just `object`, for path ['a', 'b'], this is `object[a]`
26
+ export function getPropertyPathTarget(
27
+ object: object,
28
+ path: PropertyPath
29
+ ): PropertyTarget | undefined {
30
+ if (path.length === 0) {
31
+ return;
32
+ }
33
+
34
+ let target: unknown = object;
35
+ for (let index = 0; index < path.length - 1; index++) {
36
+ const property = path[index];
37
+ target = (target as PropertyTarget)[property];
38
+ if (target == null) {
39
+ return;
40
+ }
41
+ }
42
+ return target as PropertyTarget;
43
+ }
@@ -0,0 +1,14 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+
5
+ export default function sliceObject<ObjectType extends object, Key extends keyof ObjectType>(
6
+ object: ObjectType,
7
+ keys: readonly Key[]
8
+ ): Pick<ObjectType, Key> {
9
+ const sliced = {} as Pick<ObjectType, Key>;
10
+ for (const key of keys) {
11
+ sliced[key] = object[key];
12
+ }
13
+ return sliced;
14
+ }
@@ -0,0 +1,58 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+
5
+ import log from './log';
6
+
7
+ export type EventListener = (...data: unknown[]) => void;
8
+ export type EventListeners = Record<string, EventListener | unknown>;
9
+
10
+ export type SubscriptionMethods = {
11
+ subscribe(listener: EventListeners): void;
12
+ unsubscribe(listener: EventListeners): void;
13
+ unsubscribeAll(): void;
14
+ trigger(event: string, ...data: unknown[]): void;
15
+ hasSubscribersFor(event: string): boolean;
16
+ };
17
+
18
+ export default function subscribeMixin<Target extends object>(
19
+ target: Target
20
+ ): Target & SubscriptionMethods {
21
+ let listeners: EventListeners[] = [];
22
+
23
+ return Object.assign(target, {
24
+ subscribe(listener: EventListeners): void {
25
+ if (!listeners.includes(listener)) {
26
+ listeners.push(listener);
27
+ }
28
+ },
29
+
30
+ unsubscribe(listener: EventListeners): void {
31
+ const index = listeners.indexOf(listener);
32
+ if (index >= 0) {
33
+ listeners.splice(index, 1);
34
+ }
35
+ },
36
+
37
+ unsubscribeAll(): void {
38
+ listeners = [];
39
+ },
40
+
41
+ trigger(event: string, ...data: unknown[]): void {
42
+ for (const listener of [...listeners]) {
43
+ const handler = listener[event];
44
+ if (typeof handler === 'function') {
45
+ try {
46
+ handler.call(listener, ...data);
47
+ } catch (error) {
48
+ log('warn', `Caught exception in listener for event '${event}':`, error);
49
+ }
50
+ }
51
+ }
52
+ },
53
+
54
+ hasSubscribersFor(event: string): boolean {
55
+ return listeners.some(listener => typeof listener[event] === 'function');
56
+ }
57
+ });
58
+ }
@@ -0,0 +1,154 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ /** State shared by cooperative tasks for the current frame. */
7
+ export type TaskState = Record<string, unknown> & {user_moving_view?: boolean};
8
+
9
+ /** A cooperative task scheduled by the renderer. */
10
+ export interface TaskRecord<Value = unknown> {
11
+ id?: number;
12
+ max_time?: number;
13
+ pause_factor?: number;
14
+ pause?: number;
15
+ immediate?: boolean;
16
+ user_moving_view?: boolean;
17
+ elapsed?: number;
18
+ total_elapsed?: number;
19
+ start_time?: number;
20
+ tile_id?: unknown;
21
+ stats?: {calls: number};
22
+ promise?: Promise<Value | undefined>;
23
+ resolve?: (value: Value | PromiseLike<Value> | undefined) => void;
24
+ reject?: (reason?: unknown) => void;
25
+ run: (task: TaskRecord<Value>) => unknown;
26
+ cancel?: (task: TaskRecord<Value>) => Value | undefined;
27
+ [property: string]: unknown;
28
+ }
29
+
30
+ /** Cooperative renderer task scheduler. */
31
+ export interface TaskManager {
32
+ id: number;
33
+ queue: TaskRecord[];
34
+ max_time: number;
35
+ start_time: number | null;
36
+ elapsed?: number;
37
+ state: TaskState;
38
+ add<Value>(task: TaskRecord<Value>): Promise<Value | undefined>;
39
+ remove<Value>(task: TaskRecord<Value>): void;
40
+ process<Value>(task: TaskRecord<Value>): unknown;
41
+ processAll(): void;
42
+ finish<Value>(task: TaskRecord<Value>, value: Value): Promise<Value | undefined>;
43
+ cancel<Value>(task: TaskRecord<Value>): void;
44
+ shouldContinue<Value>(task: TaskRecord<Value>): boolean;
45
+ removeForTile(tileId: unknown): void;
46
+ setState(state: TaskState): void;
47
+ }
48
+
49
+ /** Shared renderer task scheduler. */
50
+ export const Task: TaskManager = {
51
+ id: 0,
52
+ queue: [],
53
+ max_time: 20,
54
+ start_time: null,
55
+ state: {},
56
+
57
+ add<Value>(task: TaskRecord<Value>): Promise<Value | undefined> {
58
+ task.id = Task.id++;
59
+ task.max_time = task.max_time || Task.max_time;
60
+ task.pause_factor = task.pause_factor || 1;
61
+ task.promise = new Promise((resolve, reject) => {
62
+ task.resolve = resolve;
63
+ task.reject = reject;
64
+ });
65
+
66
+ task.elapsed = 0;
67
+ task.total_elapsed = 0;
68
+ task.stats = {calls: 0};
69
+ this.queue.push(task as TaskRecord);
70
+
71
+ this.start_time = this.start_time || performance.now();
72
+ this.elapsed = performance.now() - this.start_time;
73
+ if (this.elapsed < Task.max_time || task.immediate) {
74
+ this.process(task);
75
+ }
76
+
77
+ return task.promise;
78
+ },
79
+
80
+ remove<Value>(task: TaskRecord<Value>): void {
81
+ const index = this.queue.indexOf(task as TaskRecord);
82
+ if (index > -1) {
83
+ this.queue.splice(index, 1);
84
+ }
85
+ },
86
+
87
+ process<Value>(task: TaskRecord<Value>): unknown {
88
+ if (this.state.user_moving_view && task.user_moving_view === false) {
89
+ return;
90
+ }
91
+
92
+ if (task.pause) {
93
+ task.pause--;
94
+ return true;
95
+ }
96
+
97
+ task.stats!.calls++;
98
+ task.start_time = performance.now();
99
+ return task.run(task);
100
+ },
101
+
102
+ processAll(): void {
103
+ this.start_time = this.start_time || performance.now();
104
+ for (const task of this.queue) {
105
+ if (this.process(task) !== true) {
106
+ if (!task.pause) {
107
+ task.pause = task.elapsed! > task.max_time! ? task.pause_factor : 0;
108
+ }
109
+ task.total_elapsed! += task.elapsed!;
110
+ }
111
+
112
+ this.elapsed = performance.now() - this.start_time;
113
+ if (this.elapsed >= Task.max_time) {
114
+ this.start_time = null;
115
+ break;
116
+ }
117
+ }
118
+ },
119
+
120
+ finish<Value>(task: TaskRecord<Value>, value: Value): Promise<Value | undefined> {
121
+ task.elapsed = performance.now() - task.start_time!;
122
+ task.total_elapsed! += task.elapsed;
123
+ this.remove(task as TaskRecord);
124
+ task.resolve!(value);
125
+ return task.promise!;
126
+ },
127
+
128
+ cancel<Value>(task: TaskRecord<Value>): void {
129
+ const value = task.cancel?.(task);
130
+ task.resolve!(value);
131
+ },
132
+
133
+ shouldContinue<Value>(task: TaskRecord<Value>): boolean {
134
+ task.elapsed = performance.now() - task.start_time!;
135
+ this.elapsed = performance.now() - this.start_time!;
136
+ return task.elapsed < task.max_time! && this.elapsed < Task.max_time;
137
+ },
138
+
139
+ removeForTile(tileId: unknown): void {
140
+ for (let index = this.queue.length - 1; index >= 0; index--) {
141
+ const task = this.queue[index];
142
+ if (task.tile_id === tileId) {
143
+ this.cancel(task);
144
+ this.queue.splice(index, 1);
145
+ }
146
+ }
147
+ },
148
+
149
+ setState(state: TaskState): void {
150
+ this.state = state;
151
+ }
152
+ };
153
+
154
+ export default Task;
@@ -0,0 +1,26 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ export type ThreadState = {
7
+ is_worker: boolean;
8
+ is_main: boolean;
9
+ };
10
+
11
+ // Node/SSR is neither a browser main thread nor a Web Worker. In particular,
12
+ // do not install worker-only global shims while a server imports the package.
13
+ const isMain = typeof window !== 'undefined' && typeof Window !== 'undefined' &&
14
+ typeof HTMLDocument !== 'undefined' && window instanceof Window && window.document instanceof HTMLDocument;
15
+ const isWorker = typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope;
16
+ const Thread: ThreadState = {is_worker: isWorker, is_main: isMain};
17
+
18
+ if (isWorker) {
19
+ // Patch for third-party libraries that require these globals to be present, specifically
20
+ // FontFaceObserver. This allows that library to load on worker threads.
21
+ const workerWindow = {document: {}};
22
+ Reflect.set(globalThis, 'window', workerWindow);
23
+ Reflect.set(globalThis, 'document', workerWindow.document);
24
+ }
25
+
26
+ export default Thread;