Version 2.1 — © 1996-2003 Christian Cohnen
Originally a Java applet (1996). The original Java applet code was transpiled to JavaScript/Canvas in 2026 so the effect can run in modern browsers without a Java plugin. The JavaScript version uses Canvas pixel manipulation with the same integer-only wave kernel.
The Water applet simulates a rippling water surface in real time. Two height fields are updated each frame using a Laplacian kernel that propagates waves across the grid. A small damping factor makes sure waves gradually fade out instead of bouncing forever. The displacement is then added to each pixel's color — bright where the surface rises, dark where it dips — which gives the typical light-refraction look you'd expect from water.
Raindrops fall at a configurable rate, ships cruise along sinusoidal paths generating bow waves, and moving the mouse over the surface creates ripples. You can lay a background image under the water or just use a solid color.
This kind of 2D wave simulation was a classic effect in the Atari ST, Amiga and PC demoscene of the 1990s. The entire core loop runs on integer shifts and additions only — no multiplications, no divisions — which was essential on the hardware of that era and still keeps things fast today.
| Name | Type | Description | Default | Required |
|---|---|---|---|---|
color | Color | Surface color when no image is set | #0000FF (blue) | no |
image | filename | Background image (scaled to applet size) | – | no |
raindrops | int | Raindrops per 10 seconds | 4 | no |
ships | int | Number of ships cruising the surface | 0 | no |
link | URL | Link target when applet is clicked | – | no |
FPS | – | Enables FPS counter (presence enables it, no value needed) | off | no |
<applet archive="Water.jar"
code="Water.class" width="100" height="100">
<param name="link" value="https://www.chriscohnen.de">
<param name="FPS">
<param name="color" value="#0000AF">
<param name="raindrops" value="25">
</applet>
The JavaScript port uses the same Laplacian wave kernel and integer damping but renders into an HTML5 <canvas> via ImageData.
Mouse interaction creates ripples just like the original applet.
<canvas id="game" width="100" height="100"></canvas>
<script>var WATER_CFG = { color: "#0000AF", raindrops: 25 };</script>
<script src="water.min.js"></script>
| Name | Type | Description | Default |
|---|---|---|---|
color | string | Surface color hex when no image | "#0000FF" |
image | string | ID of hidden background <img> element | null |
raindrops | int | Raindrops per 10 seconds | 4 |
ships | int | Number of ships cruising the surface | 0 |
link | string | URL to open on click | null |
Originally a Java applet (1996). The original used Java's MemoryImageSource
with a PixelGrabber for background image scanning. The JavaScript version uses Canvas
ImageData with a Uint32Array view for equivalent pixel manipulation.
The Laplacian wave kernel and integer damping (31/32 via shift) are preserved exactly from the original.