【Rain Effect】 is a visually stunning rain animation JavaScript library, and its classic implementation has been showcased on the homepage of this site. However, the library is relatively old, lacks configuration capabilities, and is difficult to maintain. This article documents our complete practical process of refactoring its logic, decoupling dependencies, and encapsulating it as a React component.

If you have already visited the homepage of this site Homepage, you might be amazed by the realistic raindrop effect on the landing page. This effect comes from an open-source project RainEffect (hereinafter referred to as RE). The project implements these magical raindrop effects using webgl and has been open-sourced on GitHub.
However, due to the long-term lack of maintenance of this project, even for front-end developers, it is difficult to elegantly integrate into modern projects. This article will detail how to introduce and render this effect in actual projects, and gradually refactor it into maintainable code that supports TypeScript. The whole process does not involve complex logic—let’s get started.
If you do not want to install the refactored npm package, you can also choose to directly include the original JS source code and quickly render the raindrop effect in HTML. This was the implementation method used by this site before completing the refactoring, suitable for temporary integration or lightweight usage.
Download this file (RE) and place it in your directory; we will later introduce this file via a script tag.
I have only used the index.min.js image background so far, so it is unknown whether the other versions work properly. If you wish to use another version (for example, video background), you can download index3.min.js.
Click here to view the rendering effects of each version.
Introduce the downloaded file into your project via a script tag, for example:
js
At the same time, you need to create a canvas tag on your page to render the content:
js
The index.min.js code internally retrieves the canvas tag via its id attribute and renders accordingly, so the id value of the canvas must match the id value of the selector in the code file (the selector’s id in the code is container). If your canvas uses a different id, you must modify it synchronously in the code file:
js
Code modification ends here.
Simply modifying the code is not enough to render successfully, because the raindrop rendering uses resources such as background images. You need to download all files in the img folder and place them in your own project; these files will be automatically loaded during rendering.
If the image paths are correct and load normally, you should see the rendered page in your project, like this:
### Change Background Image
Place your own background image in the img folder and modify the file path in index.min.js to load your own background image:
js
It is not hard to notice that the above usage is rather cumbersome and cannot cooperate well with today’s front-end engineering workflows (such as webpack, vite). This refactoring work aims at engineering practices without modifying the core source code. The implemented features are as follows:
bash
Hereinafter, the refactored library is referred to as Arain
The default export of Arain is Rain. You can initialize a Rain instance through this class. The basic structure of the class is as follows:
typescript
An example of rendering with an image as background is as follows:
typescript
./drop-color.png and ./drop-alpha.png are required rendering resources; the canvas synthesizes raindrops using these two images. You can download them here.
In the code, #aling-rain-cover is the id of the canvas element in your page; the animation will finally be rendered into your canvas, so your code also needs the corresponding canvas tag, like this:
html
Starting from version v0.1.0, video backgrounds are supported. Unlike image backgrounds, when initializing the instance, you no longer need to set the bg/fg properties; instead, specify the video element to render via the video property:
typescript
Here, video is the id of your video element; the video content will be rendered onto the page. This means you need to manage the video element yourself, like this:
html
If rendering is successful, the final effect will be as follows:
:::info
We recommend using bright videos as the rendering source, because raindrop rendering is based on real-time video content. If the video is not bright enough, you may render black raindrops. `(>﹏<)′
:::
Initializes the instance, reloads image resources (an asynchronous operation), and starts rendering. Repeating calls will start multiple rendering processes; redundant rendering processes are not automatically closed, which may cause your page to lag. Therefore, terminate the previous rendering before starting.
typescript
Terminates a rendering process, clears all animation rendering and variables to release memory, e.g., call it when routing changes.
typescript
Background image of the raindrop canvas.
Minimum radius of raindrops, default 10
Maximum radius of raindrops, default 40
typescript
##### maxDrops
Number of large raindrops, default 900
typescript
At this point there is only one raindrop on the page.