Wind field and weather data
The wind-field data format, interpolation utilities, and wind-layer APIs are experimental and may change. The particle simulation runs on the graphics device; the field-building and explicit sampling utilities described here are deliberately backend-independent.
A WindField is the shared, indexed weather forecast used by WindLayer, ParticleLayer,
ElevationLayer examples, DelaunayCoverLayer, and DelaunayInterpolation. Build the field
once and reuse the same object throughout an animation.
Import
import {
createWindField,
getWindBounds,
parseWindData,
sampleWindField,
triangulateWindStations,
type WindBounds,
type WindField,
type WindFieldOptions,
type WindMeasurement,
type WindSample,
type WindStation,
type WindTriangle
} from '@deck.gl-community/geo-layers';
Load the original forecast
import {
createWindField,
parseWindData,
type WindStation
} from '@deck.gl-community/geo-layers';
const dataUrl =
'https://raw.githubusercontent.com/visgl/deck.gl-data/master/examples/wind';
const [stations, weather] = await Promise.all([
fetch(`${dataUrl}/stations.json`).then(response => response.json()) as Promise<WindStation[]>,
fetch(`${dataUrl}/weather.bin`).then(response => response.arrayBuffer())
]);
const frames = parseWindData(weather, stations.length);
const windField = createWindField(stations, frames);
The original weather.bin contains 72 hourly forecast frames. Each weather station stores its
frames consecutively, with three unsigned 16-bit values per frame:
[direction, speed, temperature]. parseWindData converts this station-major binary layout into
frame-major measurements.
Station coordinates
The historical dataset uses positive-west longitude:
const station: WindStation = {
name: 'Denver',
long: 104.99,
lat: 39.739,
elv: 1609
};
const deckPosition = [-station.long, station.lat, station.elv];
createWindField, getWindBounds, triangulateWindStations, and the wind layers perform this
conversion internally. Do not pre-negate station.long before passing the original dataset to
these utilities.
parseWindData(buffer, stationCount, frameCount?)
const frames: WindMeasurement[][] = parseWindData(weather, stations.length, 72);
buffer: station-majorArrayBuffercontaining packedUint16measurements.stationCount: number of weather stations represented in every frame.frameCount: number of forecast frames; defaults to72.- Returns frame-major
[direction, speed, temperature]measurements. - Throws
RangeErrorwhen the dimensions or binary length are invalid.
Direction is measured in eighth-turns: 0 points east, and successive values rotate
counterclockwise by 45 degrees. sampleWindField converts the result into radians and an
eastward/northward velocity.
createWindField(stations, frames, options?)
const windField: WindField = createWindField(stations, frames);
const options: WindFieldOptions = {
triangles: triangulateWindStations(stations)
};
const fieldWithExistingTriangles = createWindField(stations, frames, options);
Creates the shared forecast, computes geographic bounds and observed value ranges, and indexes the
station triangulation for fast repeated sampling. By default, the robust Delaunay triangulation is
computed once with delaunator; provide options.triangles when reusing a known station mesh.
WindField exposes stations, frames, triangles, bounds, speedRange, and
temperatureRange. Its spatialIndex is an internal implementation detail, not a public
construction API.
sampleWindField(field, position, time?)
const sample: WindSample | null = sampleWindField(windField, [-104.99, 39.739], 12.5);
if (sample) {
console.log(sample.direction, sample.speed, sample.temperature);
console.log(sample.elevation, sample.velocity);
}
Interpolates measurements spatially inside the station triangulation and temporally between
adjacent forecast frames. Fractional times wrap around the forecast; positions outside measured
station coverage return null instead of being extrapolated.
WindSample.direction is in radians, velocity is [east, north], and elevation is in meters.
triangulateWindStations(stations)
const triangles: WindTriangle[] = triangulateWindStations(stations);
Returns station-index triples covering the real station hull. Duplicate station coordinates are ignored. Fewer than three distinct, non-collinear station positions produce an empty triangulation.
getWindBounds(stations)
const bounds: WindBounds = getWindBounds(stations);
const elevationBounds = [bounds.minLng, bounds.minLat, bounds.maxLng, bounds.maxLat];
Returns geographic west, south, east, and north limits using deck.gl longitude conventions.
GPU simulation boundary
ParticleLayer turns the shared field into cached weather textures and keeps particle positions in
GPU buffers. WebGL2 uses transform feedback; WebGPU uses compute. Explicitly calling
sampleWindField or DelaunayInterpolation.rasterize is CPU work and is not necessary for each
animation frame. Do not rebuild the field, triangulation, raster, or particle simulation on every
requestAnimationFrame.
See the complete wind showcase guide, ParticleLayer, and original wind showcase.