natural-disasters README

The project's README from github.com/Token-Gremlin/natural-disasters. As one markdown file: README.md.

ABYSSAL

A fully procedural ocean and extreme weather simulation that runs in a browser tab.

Live demo License: MIT CI Three.js WebGL2

▶ Run it in your browser

Clear sky over open ocean with a sun glitter path

ABYSSAL is a real-time cinematic ocean built entirely out of maths. There are no textures, meshes, HDRIs or sound files in this repository — every wave, cloud, foam streak, raindrop and lightning bolt is generated on the GPU at load time or per frame. The whole thing is about 400 KB of JavaScript and GLSL.

It ships with two ways to experience it: an automatic cinematic sequence that plays through a storm cycle on its own, and a sandbox where you fly the camera yourself and trigger hurricanes, tsunamis and waterspouts wherever you are looking.


Contents


Highlights

Ocean

Sky and atmosphere

Weather and disasters

Torrential rain, wind-driven spray off the crests, volumetric lightning with branching bolt geometry, waterspouts with a raymarched condensation funnel, whirlpools, hurricanes with an eye and eyewall, rogue waves and tsunamis with an asymmetric shoaling profile. Every one of them deforms the actual water surface.

Rendering

Temporal anti-aliasing, EV100 auto-exposure, bloom, depth of field, motion blur, AgX and ACES tonemapping, contrast-adaptive sharpening, chromatic aberration, film grain and vignette. Quality adapts at runtime to hold a frame budget.


Fair-weather cumulus field Trade wind conditions
Fair-weather cumulus, clear day Trade wind, Beaufort 5
Storm deck seen from below Violent storm sea state
Cumulonimbus deck, violent storm Beaufort 11, mountainous sea

Quick start

The fastest way in is the live build — it is the same bundle, deployed straight from main. To run it locally you need Node.js 20.19+ or 22.12+.

git clone https://github.com/Token-Gremlin/natural-disasters.git
cd natural-disasters
npm install
npm run dev

Then open the URL Vite prints (usually http://localhost:5173).

To build a static bundle you can host anywhere:

npm run build     # outputs to dist/
npm run preview   # serve the built bundle locally

The build has no runtime dependencies beyond the bundled JavaScript — drop dist/ on any static host and it works.


Controls

The demo opens in cinematic mode, which plays an automatic sequence of acts. Press the SANDBOX button in the corner to take over.

Camera (sandbox / free fly)

Input Action
Mouse drag, or click to lock the pointer Look around
W A S D or arrow keys Move
E or Space Ascend
Q Descend
Shift Sprint (5×)
Ctrl Crawl (0.18×)
Mouse wheel Zoom (field of view)

Events

Each event spawns where the camera is looking and pulls the camera to a vantage point that frames it.

Key Event
1 Lightning burst
2 Toggle rain
3 Waterspout
4 Maelstrom (whirlpool)
5 Hurricane
6 Rogue wave
7 Tsunami
0 Calm everything

The sandbox panel also exposes condition presets (clear day, trade wind, golden hour, overcast, squall, violent storm, night storm) and live sliders for sun angle, cloud cover, cloud density, cloud base, anvil, haze, wind, swell, choppiness, rain, spray, camera speed and zoom.


URL parameters

Parameter Values Effect
preset potato low medium high ultra Force a quality preset instead of auto-detecting from the GPU
adaptive 0 Disable runtime quality scaling (useful for benchmarking)
profile 1 Enable the per-pass GPU timer
act integer Jump straight to an act of the cinematic sequence
director 0 Disable the automatic director
debug integer Surface a debug channel (normals, foam, Fresnel, roughness, …)
paused 1 Boot paused

Example: http://localhost:5173/?preset=ultra&adaptive=0&profile=1


Quality presets

Preset Render scale Ocean grid FFT Cloud steps Rain + spray Intended for
potato 0.60 128 × 84 128 34 15 k Software rendering, very old hardware
low 0.72 176 × 110 128 48 38 k Older integrated GPUs
medium 0.85 240 × 150 256 66 88 k Entry-level discrete GPUs
high 1.00 340 × 210 256 96 176 k Mainstream discrete GPUs
ultra 1.00 480 × 300 256 148 330 k High-end discrete GPUs

potato also drops depth of field and motion blur. Temporal anti-aliasing stays on at every preset, because the cloud march depends on it to resolve.

The preset is auto-detected from the unmasked WebGL renderer string. If the frame budget is missed for long enough, adaptive quality first lowers the internal resolution and then steps down a whole preset.


How it works

Everything is generated at runtime. At boot the app bakes its own texture set — foam and bubble rafts, ripple normals, a curl field, a synoptic weather map, a 128³ Perlin-Worley cloud shape volume and a 32³ detail volume — then solves the atmospheric scattering LUTs. Nothing is fetched from disk.

The ocean is a sum of three FFT cascades at different spatial scales. Each frame the spectrum is advanced in time and inverted with a butterfly IFFT into displacement and derivative textures, from which the shader recovers normals and the surface Jacobian. The Jacobian and the local wave steepness feed a foam buffer that accumulates and decays, which is what makes whitecaps persist behind a breaking crest instead of flickering.

The surface is drawn as a projected grid: a screen-space mesh whose vertices are raycast onto the water plane, giving uniform pixel density and a correct horizon at any altitude. Disaster events are analytic height fields evaluated in both GLSL and JavaScript — the shader uses them to displace the surface, and the CPU mirror lets the camera surf a tsunami instead of being swallowed by it.

The clouds are raymarched through a shell between the cloud base and top. Coverage, type and base altitude come from the weather map; the Perlin-Worley volume supplies the billow shape; two curl-warped octaves of the detail volume erode the silhouette into cauliflower. Lighting is a short march toward the sun with a Beer-Powder term and multiple scattering octaves. The march is amortised over a 4×4 Bayer grid and reprojected temporally, then reconstructed to full resolution with a Catmull-Rom bicubic filter that blends toward a wider kernel only while the camera is moving.

The frame is rendered into an HDR target with a velocity buffer, resolved with TAA, metered for auto-exposure through a log-luminance mip chain, then run through bloom, depth of field, motion blur, tonemapping and sharpening.


Project layout

src/
  main.js                 entry point and boot sequence
  core/
    App.js                render loop, resize, frame graph
    Quality.js            presets, GPU detection, adaptive scaling
    SharedUniforms.js     the single source of global uniform state
    GpuProfiler.js        per-pass timing via EXT_disjoint_timer_query_webgl2
  ocean/
    OceanFFT.js           spectrum, time evolution, butterfly IFFT cascades
    OceanMesh.js          projected grid, surface shading, event raymarch
    OceanSampleGLSL.js    shared sampling and disaster field functions
  sky/
    Atmosphere.js         scattering LUTs
    AtmosphereGLSL.js     shared atmosphere shader code
    SkyRenderer.js        sky dome and env probe
    Clouds.js             volumetric cloud march, reprojection, upsample
  weather/
    Weather.js            weather state and Beaufort mapping
    Director.js           cinematic acts, event spawning, CPU event field
    Lightning.js          branching bolt geometry and flicker
    Waterspout.js         raymarched condensation funnel
    Precipitation.js      rain streaks and crest spray
  post/
    PostFX.js             TAA, exposure, bloom, DOF, motion blur, tonemap
  camera/
    CinematicCamera.js    director shots, free fly, handheld shake
  gfx/
    ProceduralTextures.js all runtime texture baking
    NoiseGLSL.js          Perlin, Worley, curl and fBm
    ShadingGLSL.js        BRDF and irradiance helpers
    FullScreenPass.js     render target and pass plumbing
  ui/
    Overlay.js            cinematic HUD and debug panel
    Sandbox.js            interactive mode and event triggers
tools/                    headless test and image analysis harness

Development tools

tools/ holds a Puppeteer harness used to develop the renderer. It drives a real GPU-backed Chrome, so it can catch shader compile failures, measure frame times and take deterministic screenshots by pausing the simulation.

Start npm run dev first — the harness points at localhost:5173 by default and takes --url to point somewhere else.

# Drive the sandbox, capture named camera framings, print per-pass GPU timings
node tools/sb.mjs --tag test --look sky,sea,high --nohud

# Trigger an event and shoot it at a fixed simulation time
node tools/sb.mjs --tag tsu --do tsunami --cond storm

# Show the browser window instead of running it off-screen
node tools/sb.mjs --tag test --show

Image analysis helpers: crop.mjs magnifies a region, diff.mjs computes the mean absolute difference between two captures, seam.mjs looks for suspicious column discontinuities, px.mjs dumps pixel values along a scanline.

Captures land in tools/shots/, which is deliberately not tracked by git.


Performance

Measured on an NVIDIA GeForce GTX 1650 at 1600 × 900, preset high, adaptive scaling off:

Scene Median frame time FPS
Clear day 9.3 ms 108
Violent storm (cloud cover 0.74) 13.8 ms 72

Add ?profile=1 for a per-pass breakdown of where the frame goes.


Browser support

Needs WebGL2 with EXT_color_buffer_float. That covers current Chrome, Edge, Firefox and Safari 15+ on desktop. A discrete GPU is recommended; integrated graphics work at the lower presets.

Mobile is not a target. The projected grid and the cloud march are both far too expensive for phone-class hardware at any useful resolution.


Contributing

Contributions are welcome. Please read CONTRIBUTING.md for how the project is organised, what a good change looks like and how to verify a rendering change before opening a pull request. By taking part you agree to the Code of Conduct.


License

MIT — free for any use, including commercially. Attribution is appreciated but not required.


References

The techniques here are built on published work:

Built with Three.js and Vite.

natural-disasters (Token-Gremlin/natural-disasters)

Searching Database…

这是什么?ABYSSAL 是一个完全程序化的电影级海洋与极端天气模拟,完全在浏览器标签页中运行,渲染多级联 FFT 海浪、体积云、飓风和海啸,零外部资源,基于 Three.js、WebGL2 和 GLSL3 构建。
这是一个游戏,还是更偏向交互式艺术演示?它是一个图形演示,不是有目标的游戏:打开时是自动电影模式,播放一整轮风暴循环,还提供沙盒模式,你可以自由飞行镜头并自行触发天气事件。
这个怎么运行?在浏览器中打开已部署的在线版本,或者克隆仓库并运行 npm install 再 npm run dev(Vite)在本地启动;npm run build 会生成可托管在任何地方的静态 dist/ 包。
运行它需要什么?本地构建或开发需要 Node.js 20.19+ 或 22.12+,Three.js 是唯一的运行时依赖,浏览器本身需要支持 EXT_color_buffer_float 的 WebGL2。
它在任何设备上都能流畅运行吗?不能——移动端明确不支持,因为屏幕空间投影网格和云层光线步进对手机级 GPU 来说开销太大;建议使用独立显卡,因为集成显卡只能在较低画质预设下流畅运行。
这个项目面向谁?它面向对实时程序化渲染技术(FFT 海洋、大气散射、体积云)感兴趣的图形程序员和着色器爱好者,也面向只想观看电影级风暴演示的人。
我怎么自己触发飓风或海啸?在沙盒模式下,数字键 1-7 会在镜头所朝的位置生成特定事件(1 闪电、5 飓风、7 海啸等),按 0 让一切平息。
为什么仓库里没有任何纹理或 3D 资源?每一道波浪、云、泡沫条纹、雨滴和闪电都是在加载时或逐帧由 GPU 程序化生成的,所以整个项目只有约 400 KB 的 JavaScript 和 GLSL,无需从磁盘读取任何东西。
它实际运行速度有多快?在 NVIDIA GTX 1650、1600x900 分辨率、'high' 预设下,晴天约 108 FPS,猛烈风暴时约 72 FPS,运行时会自适应调整画质以维持帧率预算。
我可以强制指定画质等级或进行基准测试吗?可以——在 URL 后附加 ?preset=potato|low|medium|high|ultra 可覆盖自动检测的画质,?adaptive=0 可禁用运行时缩放,?profile=1 可查看每个 pass 的 GPU 计时明细。
Size
5.2 MB
Stars
287
Updated
CommitSep 01
Age
1mo
Commits · 90 Days