Skip to content

feat: restore and document the GPU-powered wind showcase - #699

Merged
ibgreen-openai merged 3 commits into
masterfrom
codex/wind-showcase-review-fixes
Jul 27, 2026
Merged

feat: restore and document the GPU-powered wind showcase#699
ibgreen-openai merged 3 commits into
masterfrom
codex/wind-showcase-review-fixes

Conversation

@ibgreen-openai

@ibgreen-openai ibgreen-openai commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Summary

Restore Nicolas Belmonte's historical deck.gl wind showcase as reusable, documented @deck.gl-community/geo-layers APIs, preserving the original 72-hour United States weather-station forecast while moving particle advection back onto the GPU.

The reference implementation is the historical deck.gl wind showcase. The standalone and website examples import the reusable public community layers instead of carrying a second private showcase implementation.

GPU particles and performance

  • Advance up to 1,000,000 animated wind particles without production CPU readbacks.
  • Use transform-feedback ping-pong buffers and native single-vertex point primitives on WebGL2.
  • Use WGSL compute and GPU-buffer-backed rendering on WebGPU.
  • Cache interpolated weather textures and preserve simulation state between layer updates.
  • Fade and respawn particles progressively; discard invalid coverage and overlong reset segments.
  • Retain static terrain and throttle CPU-interpolated arrow updates.
  • Add a debounced density slider from 1,000 to 1,000,000 particles; default to 100,000.
  • Measured the million-particle browser scene at approximately 48–59 fps on the development machine.

Terrain, data, and review feedback

  • Restore illuminated, extruded mountain terrain from the original elevation image using separable Gaussian smoothing, 24× vertical exaggeration, and a tighter terrain mesh.
  • Preserve the station-derived Delaunay surface as an optional interpolation-debug layer rather than using it as mountain terrain.
  • Replace fragile fixed super-triangle construction with robust delaunator station triangulation, including skinny-hull regression coverage.
  • Preserve the original positive-west station format, cyclic forecast interpolation, and cached spatial indexing.
  • Enable natural camera rotation and tilt up to 85 degrees.
  • Mount the same standalone implementation in the gallery and all inline wind documentation.
  • Clearly distinguish browser-verified portable GPU particle simulation from remaining upstream WebGPU terrain, polygon, and path limitations.

Documentation and public API

All new wind surfaces are explicitly marked work in progress.

  • Add a complete, runnable wind showcase developer guide.
  • Add a dedicated weather format, station coordinates, triangulation, and field API reference.
  • Expand ParticleLayer, WindLayer, ElevationLayer, DelaunayCoverLayer, and DelaunayInterpolation references with working code and live inline examples.
  • Register the guide and all six API references in the geospatial documentation sidebar.
  • Add comprehensive TSDoc for public wind types, properties, classes, methods, and field utilities.
  • Export and test WindFieldOptions and complete public field-utility import coverage.
  • Update package and documentation overviews, v9.4 release notes, upgrade guidance, and the WebGL2/WebGPU support matrix.
  • Document the gallery, one-million-particle slider, terrain controls, and historical showcase provenance.

Validation

  • Root dependency installation and full package/type/declaration build.
  • Complete Node suite: 168 test files, 1,414 passed, 9 previously skipped.
  • Commit hooks independently reran lint and all 1,414 passing tests.
  • Focused weather, robust triangulation, GPU shader, public export, and reusable-layer tests.
  • Wind terrain-smoothing and device-integration example tests.
  • Standalone wind production build.
  • Real Chromium WebGL2 full-scene and WebGPU compute/rendering tests: 3 passed.
  • Website dependency installation and complete Docusaurus production build.
  • All seven wind documentation routes verified in the generated static site.
  • Final yarn lint-fix and whitespace/diff review.
  • No generated screenshots or unrelated working-tree changes included.

WebGPU compatibility

ParticleLayer and the backend-independent forecast utilities are verified on WebGL2 and WebGPU. The complete mountain-and-arrows showcase remains work in progress on WebGPU because TerrainLayer, SolidPolygonLayer, and PathLayer depend on upstream backend support.

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown

Coverage

Stmts: 51.03% ▼-0.14% | Branch: 42.11% ▼-0.07% | Funcs: 49.21% ▼-0.08% | Lines: 51.14% ▼-0.14%

Test Files 168 passed (168)

@ibgreen-openai ibgreen-openai changed the title fix: restore GPU-powered million-particle wind showcase feat: restore and document the GPU-powered wind showcase Jul 27, 2026
@ibgreen-openai
ibgreen-openai marked this pull request as ready for review July 27, 2026 13:16
@ibgreen-openai
ibgreen-openai merged commit 4c91559 into master Jul 27, 2026
4 checks passed
@ibgreen-openai
ibgreen-openai deleted the codex/wind-showcase-review-fixes branch July 27, 2026 13:20

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae9a0c7da5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +84 to +87
nextParticlePosition = vec4(
nextPosition,
wind.z * windParticle.elevationScale + windParticle.surfaceOffset,
age

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resample elevation after choosing a respawn position

When a particle expires or leaves valid coverage, the shader chooses a new nextPosition but still derives its elevation from wind, which was sampled at the old position. Invalid particles therefore respawn at surfaceOffset, while expired particles inherit unrelated terrain elevation; on the next update the altitude is corrected and can produce a large vertical trail segment. The WGSL path mirrors this logic, so both backends should resample elevation at the selected candidate position.

Useful? React with 👍 / 👎.

Comment on lines +408 to +413
const fromDirection = from[0] % WIND_DIRECTION_EAST.length;
const toDirection = to[0] % WIND_DIRECTION_EAST.length;
east +=
weight *
((1 - frameMix) * WIND_DIRECTION_EAST[fromDirection] +
frameMix * WIND_DIRECTION_EAST[toDirection]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Compute fractional direction vectors instead of indexing the table

When callers construct a WindField with fractional direction values, which are allowed by the public WindMeasurement number type and were supported by the previous trigonometric calculation, WIND_DIRECTION_EAST[fromDirection] and its peers evaluate to undefined. The subsequent zero-vector guard does not catch the resulting NaNs, so sampleWindField returns a non-null sample with invalid direction and velocity. Compute these values trigonometrically or restrict and validate the public input before indexing.

Useful? React with 👍 / 👎.

Comment on lines +99 to +103
modules: [
...shaders.modules,
windParticleTrailClip,
...(this.context.device.type === 'webgl' ? [windParticleAgeFade] : [])
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add lifetime fading on the WebGPU path

On a WebGPU device this conditional omits windParticleAgeFade from the trail shader, and the analogous head-layer conditional does the same; no other WebGPU shader consumes getParticleAge. Consequently WebGPU particles retain constant alpha and pop when respawned rather than receiving the lifetime fade promised by the ParticleLayer API documentation. Add a WGSL-compatible fade or explicitly limit the documented behavior to WebGL.

Useful? React with 👍 / 👎.

Comment on lines +136 to +139
model.shaderInputs.setProps({
windParticlePoint: {
color: [color[0] / 255, color[1] / 255, color[2] / 255, (color[3] ?? 255) / 255],
pointSize: Math.max(1, pointRadiusPixels * 2)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply inherited opacity to WebGL particle heads

When a consumer sets ParticleLayer's inherited opacity below 1 on WebGL, this custom point shader receives alpha derived only from color; unlike the trail LineLayer and the WebGPU ScatterplotLayer, it never multiplies by the layer opacity. This leaves particle heads brighter or visible while their trails correctly fade, so the uniform alpha should incorporate this.props.opacity or use deck.gl's standard layer/color shader handling.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants