Noureddine RAMDI / epanet-js: running EPANET water modeling fully in the browser with native canvas rendering

Created Mon, 04 May 2026 10:23:01 +0000 Modified Sat, 23 May 2026 20:41:27 +0000

epanet-js/epanet-js

EPANET is a widely used water distribution modeling engine originally written in C by the EPA. epanet-js takes this legacy C codebase and ports it into a fully client-side NextJS web app that runs entirely in the browser. The project tackles the challenging mix of native dependencies and browser constraints to deliver a usable water modeling tool without server-side processing.

How epanet-js runs EPANET in the browser

At its core, epanet-js is a NextJS application written in TypeScript that wraps and ports the original EPANET engine to run client-side. It builds on top of Placemark, a higher-level framework, and uses the node-canvas library for rendering the graphical output to an HTML5 canvas element. This approach means the project still depends on native C/C++ libraries such as libpixman, libcairo, libpango, and libgif because node-canvas uses these under the hood for 2D graphics rendering.

Despite being a “browser app,” epanet-js requires a C/C++ toolchain and these native libraries to build and run the canvas rendering layer. This is a tradeoff: it brings powerful native graphics capabilities into the browser but at the cost of complicating the build environment and limiting platform compatibility. The project uses pnpm as its package manager and includes typical NextJS tooling like linting, type checking, and testing, all written in TypeScript.

Authentication and secret management are handled via cloud functions, indicating some backend infrastructure to support user management and possibly licensing or usage control.

One notable aspect is the licensing: epanet-js uses the FSL-1.1-MIT license, which restricts commercial use for two years after each commit before it transitions to MIT. This dual-licensing approach is unusual and worth understanding if considering this for commercial use.

What stands out technically about epanet-js

The standout technical challenge is porting a mature, native C library designed for desktop use into a browser environment without sacrificing performance or graphical fidelity. Using node-canvas allows leveraging native 2D drawing capabilities rather than relying solely on HTML5 canvas JavaScript APIs, which might be less performant or feature-rich.

The codebase is surprisingly clean and modern, fully TypeScript-based, with standard NextJS project setup and tooling. This suggests good developer experience for contributors familiar with modern JavaScript frameworks.

However, there are tradeoffs and limitations. The dependency on native libraries means that building and running the project requires a robust C/C++ toolchain and specific native dependencies installed on the host system. This complicates setup, especially on non-Linux platforms. For example, Apple Silicon users face additional hurdles due to node-canvas lacking a prebuilt binary for that architecture, requiring manual build steps.

The architecture prioritizes running everything client-side, which means no server-side processing for the modeling engine itself, reducing backend infrastructure but increasing client complexity.

The dual licensing approach also introduces complexity for commercial adopters, as they must track license transitions per commit.

Getting started with epanet-js

Install dependencies

Before installing epanet-js, you will need a functional C/C++ toolchain, as well as installing the following libraries:

  • libpixman
  • libcairo
  • libpango
  • libgif

On Ubuntu / Debian systems, you can install them by running:

sudo apt update
sudo apt install libpixman-1-dev
sudo apt install libcairo-dev
sudo apt install libpango1.0-dev
sudo apt install libgif-dev

Then, run:

pnpm install
Issues with Apple Silicon

We use the node-canvas library and the version we use does not include a packaged build for Apple Silicon. There is a build script available but pnpm does not launch it automatically. If you run into problems try the following:

  1. Manually install the dependencies to run the build script official documentation
  2. Manually execute the canvas package build script
cd node_modules/canvas
npm run install

Configuration

Copy the contents from .env.example to .env and edit with the values from your accounts.

Dev server

You can start the dev server with the following command.

pnpm dev

Visit http://localhost:3000.

Notice: if you see a ChunkLoadError, try refreshing the page.

Run tests

pnpm test

Or in watch mode:

pnpm test:watch

Check types

pnpm check-types

Or in watch mode:

pnpm check-types:watch

Run linter

pnpm lint

Pre-commit hook

To prevent pushing code that has linter or types errors you can add to .git/hooks/pre-commit the following:

#!/bin/sh
echo "Running type check..."
pnpm run check-types || exit 1

echo "Running lint..."
pnpm run lint || exit 1

echo "✅ All checks passed!"

who epanet-js is for

epanet-js is relevant if you need a water distribution modeling tool that runs entirely in the browser without server dependencies, and you are comfortable with the complexity of native build dependencies. It’s a good fit for developers wanting to embed EPANET modeling into web apps or educational tools with client-side execution.

The tradeoff is clear: you gain client-side independence and graphical fidelity via native canvas rendering but lose simplicity in setup and cross-platform compatibility. The Apple Silicon situation is a known pain point.

The licensing model also restricts commercial usage in the short term, so it’s more suited for research, education, or personal projects unless you track license changes carefully.

Overall, epanet-js is a solid technical achievement in porting a legacy engineering tool into a modern web environment, balancing native performance with browser constraints. It’s worth understanding if your project needs EPANET capabilities in the browser and you can handle the build complexity.


→ GitHub Repo: epanet-js/epanet-js ⭐ 185 · TypeScript