Skip to content

Commit b0fc760

Browse files
authored
feat: video export works with effects (#3373)
* feat: video export works with effects Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * improve docs for effects and video capture Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * tooltip fixes Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * fix test cover Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> * fix test and init for effects Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com> --------- Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>
1 parent 506e552 commit b0fc760

16 files changed

Lines changed: 461 additions & 20 deletions

File tree

docs/user-guides/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,22 @@ This guide will teach you how to perform data analysis in Kepler.gl by adding da
6262
* [Display legend](./m-map-settings.md#display-legend)
6363
* [Split maps](./m-map-settings.md#split-maps)
6464

65+
#### [Effects](./effects.md)
66+
* [Light & Shadow](./effects.md#light--shadow)
67+
* [Post-processing (Ink, Blur, Sepia, …)](./effects.md#ink)
68+
* [Distance Fog](./effects.md#distance-fog)
69+
* [Surface Fog](./effects.md#surface-fog)
70+
6571
#### [SQL Data Explorer](./sql-data-explorer.md)
6672

6773
#### [AI Assistant](./ai-assistant.md)
6874

6975
#### [Time playback](./h-playback.md)
7076

7177
#### [Save and export](./k-save-and-export.md)
78+
* [Export Image](./k-save-and-export.md#export-image)
79+
* [Export Data](./k-save-and-export.md#export-data)
80+
* [Export Map](./k-save-and-export.md#export-map)
81+
* [Export Video](./k-save-and-export.md#export-video)
7282

7383
#### [FAQ](./i-FAQ.md)

docs/user-guides/effects.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# Effects
2+
3+
Kepler.gl provides a collection of visual effects that can be applied to your map as post-processing passes. Effects range from lighting and atmospheric simulation to artistic color grading and blur filters. Each effect is configurable through its own set of parameters.
4+
5+
You can add an effect from the **Effects** panel in the side bar. Multiple effects can be stacked and reordered; they are applied in order from top to bottom.
6+
7+
> **Limitation:** Only one Light & Shadow effect and one fog effect (either Distance Fog or Surface Fog) can be active at a time.
8+
9+
---
10+
11+
## Table of contents
12+
13+
- [Light & Shadow](#light--shadow)
14+
- [Ink](#ink)
15+
- [Brightness & Contrast](#brightness--contrast)
16+
- [Hue & Saturation](#hue--saturation)
17+
- [Vibrance](#vibrance)
18+
- [Sepia](#sepia)
19+
- [Dot Screen](#dot-screen)
20+
- [Color Halftone](#color-halftone)
21+
- [Noise](#noise)
22+
- [Blur (Triangle)](#blur-triangle)
23+
- [Blur (Zoom)](#blur-zoom)
24+
- [Blur (Tilt Shift)](#blur-tilt-shift)
25+
- [Edge Work](#edge-work)
26+
- [Vignette](#vignette)
27+
- [Magnify](#magnify)
28+
- [Hexagonal Pixelate](#hexagonal-pixelate)
29+
- [Distance Fog](#distance-fog)
30+
- [Surface Fog](#surface-fog)
31+
32+
---
33+
34+
## Light & Shadow
35+
36+
Simulates realistic sun lighting and shadow casting based on time of day and geographic location. Useful for visualizing how sunlight and shadows interact with 3D buildings or extruded layers throughout the day.
37+
38+
| Parameter | Type | Range | Default | Description |
39+
| --- | --- | --- | --- | --- |
40+
| timestamp | number | 0 – MAX || The point in time used to compute sun position. Controlled via the date/time picker and timezone selector in the UI. |
41+
| shadowIntensity | number | 0 – 1 | 0.5 | Opacity of cast shadows. `0` means invisible shadows, `1` means fully opaque black shadows. |
42+
| sunLightIntensity | number | 0 – 1 | 1 | Brightness of the directional sun light. Higher values produce stronger highlights on illuminated surfaces. |
43+
| ambientLightIntensity | number | 0 – 1 | 1 | Brightness of the non-directional ambient fill light. Raising this reduces the overall contrast between lit and shadowed areas. |
44+
| shadowColor | color | 0 – 255 per channel | `[0, 0, 0]` (black) | The RGB color tint applied to shadow regions. |
45+
| sunLightColor | color | 0 – 255 per channel | `[255, 255, 255]` (white) | The RGB color of the directional sun light. Use warm tones (e.g. orange) to simulate sunrise/sunset. |
46+
| ambientLightColor | color | 0 – 255 per channel | `[255, 255, 255]` (white) | The RGB color of the ambient fill light. |
47+
48+
---
49+
50+
## Ink
51+
52+
Applies an ink-wash artistic style that darkens edges and creates a hand-drawn, pen-and-ink appearance. Works well for stylized or illustrative map presentations.
53+
54+
| Parameter | Type | Range | Default | Description |
55+
| --- | --- | --- | --- | --- |
56+
| strength | number | 0 – 1 | 0 | Intensity of the ink effect. `0` leaves the image unchanged; `1` applies the strongest ink wash. |
57+
58+
---
59+
60+
## Brightness & Contrast
61+
62+
Adjusts the overall brightness and contrast of the map. A simple but powerful way to correct exposure or create high-contrast or washed-out looks.
63+
64+
| Parameter | Type | Range | Default | Description |
65+
| --- | --- | --- | --- | --- |
66+
| brightness | number | -1 – 1 | 0 | Shifts the luminance of every pixel. Negative values darken the image; positive values brighten it. |
67+
| contrast | number | -1 – 1 | 0 | Adjusts the tonal range. Negative values flatten the image toward mid-gray; positive values push darks darker and lights lighter. |
68+
69+
---
70+
71+
## Hue & Saturation
72+
73+
Shifts the color hue and adjusts saturation across the entire map. Useful for creating color themes, correcting white balance, or completely desaturating the view.
74+
75+
| Parameter | Type | Range | Default | Description |
76+
| --- | --- | --- | --- | --- |
77+
| hue | number | -1 – 1 | 0 | Rotates all colors around the color wheel. `-1` and `1` both represent a full 180° rotation; `0` is unchanged. |
78+
| saturation | number | -1 – 1 | 0.25 | Controls color intensity. `-1` produces a fully grayscale image; positive values make colors more vivid. |
79+
80+
---
81+
82+
## Vibrance
83+
84+
Selectively boosts the intensity of muted colors without oversaturating already vivid ones. Produces a more natural-looking color enhancement compared to uniform saturation.
85+
86+
| Parameter | Type | Range | Default | Description |
87+
| --- | --- | --- | --- | --- |
88+
| amount | number | -1 – 1 | 0.5 | Strength of the vibrance adjustment. Positive values boost muted colors; negative values desaturate them. |
89+
90+
---
91+
92+
## Sepia
93+
94+
Applies a warm brownish tone reminiscent of aged photographs. Useful for giving the map a vintage or historical aesthetic.
95+
96+
| Parameter | Type | Range | Default | Description |
97+
| --- | --- | --- | --- | --- |
98+
| amount | number | 0 – 1 | 0 | Blend factor between the original image and the sepia-toned version. `0` is unchanged; `1` is fully sepia. |
99+
100+
---
101+
102+
## Dot Screen
103+
104+
Converts the image into a pattern of monochrome dots, resembling classic newspaper halftone printing. Creates a pop-art or retro printed look.
105+
106+
| Parameter | Type | Range | Default | Description |
107+
| --- | --- | --- | --- | --- |
108+
| angle | number | 0 – π/2 | 0 | Rotation angle of the dot grid in radians. |
109+
| size | number | 1 – 20 | 1 | Diameter of each dot in pixels. Larger values produce coarser patterns. |
110+
| center | array [x, y] | 0 – 1 each | `[0.5, 0.5]` | Normalized screen position of the pattern origin. `[0, 0]` is the top-left corner; `[1, 1]` is the bottom-right. |
111+
112+
---
113+
114+
## Color Halftone
115+
116+
Simulates CMYK color halftone printing with separate dot patterns for each color channel. Each channel is rendered at a slightly different angle, mimicking the look of commercial print media.
117+
118+
| Parameter | Type | Range | Default | Description |
119+
| --- | --- | --- | --- | --- |
120+
| angle | number | 0 – π/2 | 0 | Base rotation angle for the halftone dot grids. |
121+
| size | number | 1 – 20 | 1 | Diameter of each color dot in pixels. |
122+
| center | array [x, y] | 0 – 1 each | `[0.5, 0.5]` | Normalized screen position of the pattern origin. |
123+
124+
---
125+
126+
## Noise
127+
128+
Adds random film-grain style noise uniformly across the map. Useful for a textured analog aesthetic, adding visual warmth, or reducing visible color banding in gradients.
129+
130+
| Parameter | Type | Range | Default | Description |
131+
| --- | --- | --- | --- | --- |
132+
| amount | number | 0 – 1 | 0 | Intensity of the noise. `0` adds no noise; `1` applies heavy grain. |
133+
134+
---
135+
136+
## Blur (Triangle)
137+
138+
Applies a smooth Gaussian-like blur uniformly across the entire map. The triangle filter is a fast approximation of a Gaussian blur.
139+
140+
| Parameter | Type | Range | Default | Description |
141+
| --- | --- | --- | --- | --- |
142+
| radius | number | 0 – 100 | 0 | Blur radius in pixels. Higher values produce a stronger, softer blur. |
143+
144+
---
145+
146+
## Blur (Zoom)
147+
148+
Creates a radial motion blur that emanates outward from a center point, simulating a camera zoom or dolly effect. Focuses attention on the center while blurring the periphery.
149+
150+
| Parameter | Type | Range | Default | Description |
151+
| --- | --- | --- | --- | --- |
152+
| strength | number | 0 – 1 | 0.05 | Intensity of the zoom blur. Higher values stretch pixels more along radial lines. |
153+
| center | array [x, y] | 0 – 1 each | `[0.5, 0.5]` | Normalized screen position of the zoom origin. |
154+
155+
---
156+
157+
## Blur (Tilt Shift)
158+
159+
Simulates a tilt-shift lens effect that keeps a focal band in sharp focus while progressively blurring areas outside it. Creates an appealing miniature-model or diorama look, especially effective with overhead city views.
160+
161+
| Parameter | Type | Range | Default | Description |
162+
| --- | --- | --- | --- | --- |
163+
| blurRadius | number | 0 – 50 | 0 | Maximum blur radius in pixels applied to out-of-focus areas. |
164+
| gradientRadius | number | 0 – 400 | 0 | Size of the transition zone between sharp and blurred regions, in pixels. |
165+
| start | array [x, y] | 0 – 1 each | `[0.0, 0.0]` | Normalized screen position marking one end of the focal band. |
166+
| end | array [x, y] | 0 – 1 each | `[1.0, 1.0]` | Normalized screen position marking the other end of the focal band. |
167+
168+
---
169+
170+
## Edge Work
171+
172+
Highlights structural edges in the image using an artistic charcoal-sketch style. Renders the map as white edges on a black background, useful for creating line-art representations or emphasizing structural patterns.
173+
174+
| Parameter | Type | Range | Default | Description |
175+
| --- | --- | --- | --- | --- |
176+
| radius | number | 1 – 50 | 1 | Detection radius for edge extraction. Larger values produce thicker, bolder edges while capturing more coarse detail. |
177+
178+
---
179+
180+
## Vignette
181+
182+
Darkens the corners and edges of the map, drawing the viewer's focus toward the center. A classic photographic technique for framing content.
183+
184+
| Parameter | Type | Range | Default | Description |
185+
| --- | --- | --- | --- | --- |
186+
| amount | number | 0 – 1 | 0 | Strength of the darkening at the edges. `0` is no vignette; `1` is maximum darkening. |
187+
| radius | number | 0 – 1 | 0 | Size of the clear (unaffected) area at the center, as a fraction of the viewport. `0` starts darkening from the very center; `1` produces almost no visible vignette. |
188+
189+
---
190+
191+
## Magnify
192+
193+
Creates a circular magnifying-glass overlay at a configurable screen position. Everything inside the circle is rendered at a higher zoom level, allowing detailed inspection of a specific area without losing the surrounding context.
194+
195+
| Parameter | Type | Range | Default | Description |
196+
| --- | --- | --- | --- | --- |
197+
| screenXY | array [x, y] | 0 – 1 each | `[0.5, 0.5]` | Normalized screen position of the magnifying glass center. |
198+
| radiusPixels | number | 10 – 500 | 10 | Radius of the magnifying lens in pixels. |
199+
| zoom | number | 0.5 – 50 | 0.5 | Magnification factor inside the lens. Values above 1 zoom in; values below 1 zoom out. |
200+
| borderWidthPixels | number | 0 – 50 | 3 | Width of the circular border around the lens, in pixels. Set to 0 for no border. |
201+
202+
---
203+
204+
## Hexagonal Pixelate
205+
206+
Replaces the image with a grid of hexagonal tiles, each filled with the average color of the area it covers. Creates a mosaic or stained-glass-window aesthetic.
207+
208+
| Parameter | Type | Range | Default | Description |
209+
| --- | --- | --- | --- | --- |
210+
| scale | number | 1 – 50 | 20 | Size of each hexagonal tile in pixels. Larger values produce coarser, more abstract mosaics. |
211+
212+
---
213+
214+
## Distance Fog
215+
216+
Fades distant objects into a fog color based on their depth from the camera. Enhances the perception of depth and distance, and can be used to de-emphasize background layers or create atmospheric haze. Requires a 3D view (pitch > 0).
217+
218+
| Parameter | Type | Range | Default | Description |
219+
| --- | --- | --- | --- | --- |
220+
| density | number | 0 – 1 | 0.5 | Overall opacity of the fog. `0` is invisible; `1` is fully opaque at maximum distance. |
221+
| fogStart | number | 0 – 1 | 0.3 | Normalized depth at which the fog begins to appear. `0` starts the fog at the camera; `1` pushes it to the far plane. |
222+
| fogRange | number | 0.01 – 1 | 0.5 | Normalized depth range over which the fog ramps from transparent to fully dense. Smaller values create a sharper transition. |
223+
| fogColor | color | 0 – 255 per channel | `[217, 222, 230]` (light blue-gray) | The RGB color of the fog. |
224+
225+
---
226+
227+
## Surface Fog
228+
229+
Renders a fog layer at a specific elevation above the terrain surface. Unlike distance fog, surface fog stays at a fixed altitude and is visible from all camera angles. Useful for simulating low-lying clouds, ground mist, or valley fog. Requires a 3D view (pitch > 0).
230+
231+
| Parameter | Type | Range | Default | Description |
232+
| --- | --- | --- | --- | --- |
233+
| density | number | 0 – 1 | 0.6 | Overall opacity of the fog. `0` is fully transparent; `1` is fully opaque. |
234+
| height | number | -200 – 3000 | 50 | Elevation in meters at which the center of the fog band sits above the terrain surface. Negative values place the fog below sea level. |
235+
| thickness | number | 0 – 1000 | 50 | Vertical transition distance in meters. Controls how quickly the fog fades above and below the center elevation. Larger values produce a softer, thicker fog band. |
236+
| fogColor | color | 0 – 255 per channel | `[230, 235, 242]` (light gray-blue) | The RGB color of the fog. |
237+
| pattern | checkbox | on / off | off | When enabled, applies a procedural noise pattern to the fog density, creating a more natural, cloud-like appearance instead of a uniform flat layer. |
238+
239+
---
240+
241+
[Back to table of contents](README.md)

docs/user-guides/k-save-and-export.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ However, in the demo app, you can:
99
- [Export map as an image](#export-image).
1010
- [Export filtered or unfiltered data as a csv](#export-data).
1111
- [Export Map](#export-map)
12+
- [Export Video](#export-video)
1213
- [Share Public URL (Dropbox)](#export-dropbox)
1314

1415
## <a href="#export-image">Export Image</a>
@@ -67,6 +68,51 @@ The map config includes the current layer, filter, map style and interaction set
6768
**Note:** kepler.gl map config is coupled with loaded datasets. The __`dataId`__ key is used to bind layers, filters and tooltip settings to a specific dataset. If you try to upload a configuration with a dataset in your own kepler.gl app, you also need to make sure your dataset __`id`__ matches the __`dataId`__ in the config.
6869

6970

71+
## <a href="#export-video">Export Video</a>
72+
73+
You can record an animated video of your map and download it directly from the browser. Open the export video dialog from the toolbar by clicking **Export Video**. The dialog has two tabs — **Animation** and **Settings** — along with a live map preview.
74+
75+
### Animation tab
76+
77+
The Animation tab controls the motion and timing of the recording.
78+
79+
| Setting | Description |
80+
| --- | --- |
81+
| **Duration** | Length of the video, from 0.1 s up to 10 s. Drag the slider or type a value. Longer recordings produce larger files. |
82+
| **Camera** | An optional camera animation applied during the recording. Available presets: **None** (static camera), **Orbit (90°)**, **Orbit (180°)**, **Orbit (360°)**, **Zoom Out**, and **Zoom In**. When set to *None*, the camera stays exactly where you position it in the preview. |
83+
84+
### Settings tab
85+
86+
The Settings tab controls the output file format and quality.
87+
88+
| Setting | Description |
89+
| --- | --- |
90+
| **File Name** | Base name for the downloaded file. Defaults to `kepler.gl`. |
91+
| **Media Type** | Output format: **WebM Video** (default, small file size, supported by most browsers), **GIF** (widely compatible but larger), **PNG Sequence** (lossless frame-by-frame images), or **JPEG Sequence** (compressed frame-by-frame images). |
92+
| **Ratio** | Aspect ratio of the output: **16:9** (widescreen) or **4:3** (standard). |
93+
| **Quality** | Resolution of the output. Options depend on the selected aspect ratio. For 16:9: Good (540p), High (720p), Highest (1080p). For 4:3: Good (480p), High (960p), Highest (1440p). Higher resolutions produce sharper video but larger files. |
94+
| **File Size** | An estimated file size based on the current duration, resolution, and media type. |
95+
96+
### Preview and recording
97+
98+
The live preview in the dialog shows exactly what will be recorded, including all visible layers, active effects (brightness, fog, light & shadow, etc.), and the base map. You can pan, zoom, and tilt the map in the preview to set the starting camera position.
99+
100+
- **Play (▶)** — Preview the animation (camera movement, filter playback) without recording.
101+
- **Stop (■)** — Stop a running preview or recording.
102+
- **Render** — Start recording. The map plays through the configured animation and duration, then the browser downloads the resulting file automatically.
103+
104+
### Animated filters and trips
105+
106+
If your map has time-range filters in the *enlarged* (time-slider) view or filters synced with the layer timeline, the video recorder will animate them over the recording duration. Trip layers similarly animate their paths. The animation window mode of each filter (free, incremental, point, or interval) is respected during recording.
107+
108+
### Tips
109+
110+
- Use **WebM** format for the smallest file sizes and fastest rendering. Switch to **GIF** only when you need universal compatibility (e.g. embedding in documents that don't support video).
111+
- For the sharpest results, choose the **Highest** quality setting, but be aware that 1080p or 1440p recordings take longer and produce larger files.
112+
- Position your camera in the preview *before* clicking Render. If you selected a camera preset like *Orbit (360°)*, the orbit starts from whatever position you set.
113+
- All active [effects](./effects.md) (post-processing filters, fog, lighting) are included in the recording.
114+
115+
70116
## <a href="#export-dropbox">Share Public URL (Dropbox) </a>
71117
![Export Map to Dropbox](https://d1a3f4spazzrp4.cloudfront.net/kepler.gl/documentation/k-save-and-export-5.png "activate interactions")
72118

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const config = {
2222
// Some libraries (even if transitive) are transitioning to ESM and need additional transpilation. Relevant issues:
2323
// - tiny-sdf: https://github.com/visgl/deck.gl/issues/7735
2424
transformIgnorePatterns: [
25-
'/node_modules\\/(?!(.*@mapbox\\/tiny-sdf\\.*|@loaders\\.gl|@deck\\.gl|@deck\\.gl-community|@luma\\.gl|@hubble\\.gl|preact))',
25+
'/node_modules\\/(?!(.*@mapbox\\/tiny-sdf\\.*|@loaders\\.gl|@deck\\.gl|@deck\\.gl-community|@luma\\.gl|@hubble\\.gl|preact|maplibregl-mapbox-request-transformer))',
2626
'\\.pnp\\.[^\\/]+$'
2727
]
2828
};

src/components/src/effects/effect-configurator.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ export default function EffectConfiguratorFactory(
367367
const paramName = desc.name;
368368

369369
const rawUniform = uniforms[desc.name];
370-
if ((!rawUniform && rawUniform !== 0) || rawUniform.private) {
370+
if (rawUniform && rawUniform.private) {
371371
return null;
372372
}
373373

@@ -411,7 +411,7 @@ export default function EffectConfiguratorFactory(
411411
};
412412
}
413413
// the uniform description is {value: 0, min: 0, max: 1, ...}
414-
else if (isNumber(uniform.value)) {
414+
else if (uniform && isNumber(uniform.value)) {
415415
const rangeMin = desc.min ?? uniform.min ?? uniform.softMin ?? 0;
416416
const rangeMax = desc.max ?? uniform.max ?? uniform.softMax ?? 1;
417417
const rangeSpan = rangeMax - rangeMin;
@@ -427,6 +427,22 @@ export default function EffectConfiguratorFactory(
427427
}
428428
};
429429
}
430+
// Parameter defined in effect description but not in shader propTypes
431+
// (e.g. user-facing props that the effect maps to different GLSL uniforms)
432+
else if (desc.min !== undefined && desc.max !== undefined) {
433+
const rangeSpan = desc.max - desc.min;
434+
const step = rangeSpan > 10 ? 1 : 0.001;
435+
return {
436+
label,
437+
value1: prevValue ?? desc.defaultValue ?? 0,
438+
range: [desc.min, desc.max],
439+
value0: desc.min,
440+
step,
441+
onChange: (newValue: number[], event) => {
442+
updateEffectConfig(event, id, {parameters: {[paramName]: newValue[1]}});
443+
}
444+
};
445+
}
430446

431447
// ignore everything else for now
432448
return null;

0 commit comments

Comments
 (0)