A real-time, interactive 3D terrain erosion simulator built with Three.js, WebGL, and TypeScript. This project provides an easy way to compare different hydraulic erosion algorithms and their effects on procedurally generated terrain.
- Multiple Erosion Algorithms: Compare different approaches to hydraulic erosion simulation.
- Interactive Controls: Fine-tune erosion parameters, shader colors, and terrain generation in real-time via GUI.
- Real-time 3D Visualization: Interactive camera controls and smooth animation with Three.js.
- Procedural Terrain Generation: Simplex noise-based terrain with customizable parameters.
- Mobile Support: Responsive design with touch controls optimized for mobile devices.
- Extensible Architecture: Easy to add new erosion algorithms through the
IErosionModelinterface.
- Three.js: 3D rendering engine
- TypeScript: Type-safe JavaScript
- Vite: Fast build tool and dev server
- lil-gui: Lightweight GUI library
- simplex-noise: Procedural terrain generation
- Stats.js: Performance monitoring
- Node.js (v16 or higher recommended)
- npm or yarn
- Clone the repository:
git clone https://github.com/tessapower/hydraulic-erosion.git
cd hydraulic-erosion- Install dependencies:
npm install- Start the development server:
npm run dev- Open your browser and navigate to
http://localhost:5173/hydraulic-erosionto see the application in action.
- Mouse Wheel: Zoom in/out.
- GUI Panel: Adjust erosion parameters, terrain settings, and visual options.
- Landscape Controls:
- Regenerate terrain with different seeds.
- Adjust terrain size and resolution.
- Configure noise parameters.
- Erosion Controls:
- Select erosion algorithm.
- Adjust algorithm-specific parameters.
- Run erosion simulation step-by-step or in batch mode.
- Reset terrain to original state.
- Shader Controls:
- Modify terrain colors (flat vs steep areas).
- Configure steepness threshold for coloring.
- Comparison Controls:
- Hold right mouse button (or tap and hold on mobile) to toggle between original and eroded terrain.
hydraulic-erosion/
├── src/
│ ├── main.ts # Application entry point
│ ├── SceneManager.ts # Three.js scene orchestration
│ ├── style.css # Global styles
│ ├── erosion/
│ │ ├── BeyerErosion.ts # Beyer's hydraulic erosion implementation
│ │ ├── IErosionModel.ts # Erosion algorithm interface
│ │ ├── PBErosion.ts # Physics-based erosion implementation
│ │ └── Simulator.ts # Erosion simulation coordinator
│ ├── gui/
│ │ ├── ComparisonControls.ts # Before/after comparison controls
│ │ ├── GuiManager.ts # lil-gui integration
│ │ ├── IErosionControls.ts # Erosion controls interface
│ │ ├── LandscapeControls.ts # Terrain generation controls
│ │ ├── ShaderControls.ts # Visual/shader controls
│ │ └── SimulatorControls.ts # Simulation control panel
│ ├── shaders/
│ │ ├── terrain.fs.glsl # Fragment shader
│ │ └── terrain.vs.glsl # Vertex shader
│ ├── terrain/
│ │ ├── HeightGenerator.ts # Procedural terrain generation
│ │ ├── Landscape.ts # Terrain mesh and heightmap management
│ │ └── Mesh.ts # Mesh geometry utilities
│ └── utils/
│ ├── ColorUtils.ts # Color manipulation utilities
│ ├── MobileDetector.ts # Mobile device detection
│ └── Random.ts # Random number generation utilities
├── index.html # HTML entry point
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite build configuration
└── README.md # This file
The project is designed to be extensible. To add a new erosion algorithm:
- Create a new erosion class in
src/erosion/that implements theIErosionModelinterface:
import type {IErosionModel} from "./IErosionModel";
export class MyErosion implements IErosionModel {
readonly usesChangeMap: boolean = false; // Set to true if your algorithm uses a change map
getName(): string {
return "My Custom Erosion";
}
initialize(width: number, height: number): void {
// Initialize internal state
}
getIterations(): number {
return this.iterations;
}
setIterations(n: number): void {
this.iterations = n;
}
setSeed(seed: number): void {
// Set the random seed for reproducible results
}
simulateStep(heightMap: Float32Array, width: number, height: number): void {
// Implement one simulation step
}
erode(heightMap: Float32Array, width: number, height: number): void {
// Implement full erosion process
}
applyChanges(heightMap: Float32Array, width: number, height: number): void {
// Apply accumulated changes if your algorithm uses a change map
}
}- Register the algorithm in
SceneManager.tsby creating an instance and adding it to the Map passed toSimulatorControls:
import {MyErosion} from "./erosion/MyErosion";
// In SceneManager constructor, after creating other erosion models:
const myErosion = new MyErosion(/* parameters */);
// Add to the Map in the SimulatorControls registration:
this.guiManager.register("erosion",
new SimulatorControls(this.simulator,
new Map<string, IErosionModel>([
["Physics Based", physicsBased],
["Beyer", beyer],
["My Custom Erosion", myErosion], // Add your model here
])
)
);- Add GUI controls if your algorithm has custom parameters (see
src/erosion/PBErosion.tsfor examples).
To create a production build:
npm run buildThe built files will be in the dist/ directory, ready for deployment.
To preview the production build locally:
npm run preview- Additional erosion algorithms (thermal erosion, fluvial erosion, etc.)
- Export/import heightmap functionality
- Multithreaded simulation using Web Workers
- Water flow visualization
- Comparison view (before/after or side-by-side algorithms)
Contributions are welcome! Whether you want to add new erosion algorithms or improve existing features:
- Fork the repository
- Create a feature branch (
git checkout -b feature/new-algorithm) - Commit your changes (
git commit -m 'Add new erosion algorithm') - Push to the branch (
git push origin feature/new-algorithm) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Nick McDonald for the physics-based erosion approach.
- Hans Theobald Beyer for the original Beyer erosion algorithm implementation.
- Sebastian Lague for inspiration on terrain generation techniques.
- Three.js community for excellent documentation and examples.
For questions or suggestions, please open an issue.
Made with ❤️ and TypeScript

