earstrip is a direct replacement for earcut for polygon triangulation in WebGL. In our test it was about 6 times faster with polygons with thousands of holes, and drew broken polygons much better. With common map polygons, on x86, the advantage was just 1.1–1.2 times, far from the figures the author measured on Apple silicon.
yoDEV Tested · October 23, 2026
We ran earstrip 0.2.0 against earcut 3.2.4 (npm) and earcut.hpp 3.2.4 (C++) on the 5.7 million OpenStreetMap polygons the author publishes, on an x86 VM with Intel Xeon, Node 22, 24 and 26, GCC 13 and Clang 18. The results we report as ours come from that test.
What is polygon triangulation and what are earcut and earstrip for?
Polygon triangulation converts any outline into a set of triangles, which is all a GPU knows how to fill. Every building, park or lake that a web map or WebGL scene draws goes through that step first. earcut, from Mapbox, is the library most web map stacks use to do it: you pass it the flat coordinates and the indices where each hole starts, and it returns three vertex indices per triangle.
earstrip is the triangulator from the GLMap mobile map engine. Globus Software published it as a standalone library on October 16, 2026 and comes in two formats:
- a single C++17 header file (header-only);
- a WebAssembly build on npm whose main call takes exactly the same arguments as earcut.
It differs from earcut in two ways:
- Triangle strips. It clips the “ears” from the polygon (ear clipping) following zigzag strips, so its native output needs about 1.7 indices per triangle instead of 3.
- Broken rings. When a polygon’s rings cross or touch, it falls back to a constrained Delaunay triangulation instead of returning whatever triangles are left.
The license is ISC, the same as earcut’s.
How do you replace earcut with earstrip?
You install the package and change the import; that’s the whole diff:
npm install earstrip
- import earcut from 'earcut';
+ import earstrip from 'earstrip';
- const triangles = earcut(vertices, holes, dimensions);
+ const triangles = earstrip(vertices, holes, dimensions);
If your data comes in GeoJSON, earstrip has its own flatten(). In our test its output was identical to earcut’s flatten():
import earstrip, { flatten } from 'earstrip';
const { vertices, holes, dimensions } = flatten(geojsonPolygon.coordinates);
const triangles = earstrip(vertices, holes, dimensions);
Three practical notes from the test:
- Module format. The package is ESM only. In Node 22,
require('earstrip')also worked for us thanks to Node’srequire(esm)support. - Loading. The WebAssembly module comes embedded and compiles synchronously where the platform allows. Where it doesn’t, the README says to
await readybefore the first call (import { ready } from 'earstrip'). - C++. Copy
include/earstrip.hppto your project. It needs C++17 and nothing but the standard library. The C++ test suite in the repo passed completely on our machine.
Is earstrip faster than earcut?
It depends on your polygons and your machine. We used the author’s own benchmark data, with checksums verified: OpenStreetMap extracts from the Masovian Voivodeship (Poland) and the GLMap world map tiles. The harness was ours, against npm packages, single-threaded and best of 5 runs.
| Test | Author (Apple M4 Pro) | yoDEV (x86 Xeon) |
|---|---|---|
| 3.74 M map polygons, drop-in call, V8 | 1.44× faster | 1.08–1.19× faster |
Same, fastest API (direct.batch) |
1.74× faster | 1.21–1.38× faster |
| 56 thousand world map polygons, up to 11,674 holes in one | 7.4× faster | 5.6–6.0× faster |
| Native C++ vs earcut.hpp, 3.74 M polygons | 13% faster | GCC 13: tie · Clang 18: 12% faster |
| Native C++, world map | 6.3× faster | 4.0× faster (GCC 13) |
With polygons with many holes, the promise holds. In the world set, earcut took about 10.2 seconds in Node and earstrip between 1.7 and 1.9. It’s exactly the case where earcut pays a high price for stitching each hole to the outline, and earstrip sends straight to its Delaunay path polygons with more than 128 rings.
With common map polygons, the gain is much lower. On our x86 machine the drop-in call was 8 to 19 percent faster across Node 22, 24 and 26. The README reports 44 percent for V8 on an M4 Pro.
In native C++, it depends on the compiler. There was a tie with GCC and a 12 percent advantage with Clang, so the edge with everyday data seems compiler and CPU sensitive. We didn’t investigate why; we report what we measured.
If your data looks like ours and speed is your reason to switch, benchmark first on the hardware where your code actually runs.
What happens with self-intersecting polygons?
earstrip draws them well, and this part of what the author promises was reproduced with precision. Map data rounded to a tile grid usually ends up with rings that cross or touch, and ear clipping assumes that doesn’t happen. The main set has 82 polygons that ears can’t cut exactly. In them, earstrip’s triangles deviated from correct (even-odd) fill by 0.15 percent of pixels on average, and earcut.hpp’s by 30.7 percent. The author reports 0.15 and 31.
A minimal example shows the difference. Take a bowtie-shaped polygon that intersects itself ([0,0, 10,10, 10,0, 0,10]):
- earcut returned a single triangle and filled only one of the two lobes.
- earstrip returned two triangles that cover both, and
lastStatus()reportedapproximate.
That status lets your code know how each polygon was resolved. Possible values are exact, constrained, holes-left-out, approximate and refused. In the set of 3.74 million polygons, all but 82 came back as exact.
What are triangle strips and do you need them in WebGL?
A triangle strip is a list of indices where each new index forms a triangle with the two before it. The GPU draws n triangles with about n + 2 indices instead of 3n. earstrip writes strips natively:
- 1.66 indices per triangle in both the main set and the world set, versus 3 in a normal triangle list;
- 1.95 in a set of polygons mostly small and simple, where the gain is lower.
The drop-in earstrip() call converts strips back to a triangle list earcut style, so you only get that saving with the other APIs:
strips()returns the strips as-is.- The
directcalls write the polygon straight into WebAssembly memory and return a single index buffer ready forTRIANGLE_STRIPin WebGL 2 or WebGPU. That path was also the fastest in our benchmark.
import { strips } from 'earstrip';
const { indices, ends, clockwise } = strips(vertices, holes);
Should you switch from earcut to earstrip?
Switch if:
- Your data has polygons with many holes (coastlines, forests with clearings, world tiles). The 5 to 6 times speedup was reproduced.
- You render real map data that can have rings that cross or touch, and you’ve already seen fill errors.
- You control the index buffer and can use strips in WebGL 2 or WebGPU.
Think twice if:
- Your polygons are small and simple and speed is your only reason. On x86 the gain we measured was modest.
- Bundle size matters. As published, earstrip’s JavaScript plus its embedded WebAssembly came to about 41 KB gzipped, versus about 13 KB of unminified earcut source code. The 27 KB figure in the README is just the WebAssembly binary.
- You need a stable API. At the time of publishing this note (October 23, 2026), earstrip is at version 0.2.0, published three days earlier. Consider the earcut-compatible call stable; the rest may change before 1.0.
You? What library do you use today to triangulate polygons in your map or WebGL stack?
- Speed with complex polygons
- Drawing broken geometry well
- Smaller index buffers (triangle strips)
- I prefer another option (tell us which)
Comment below or, if this article reached you by email, reply directly to the email: your reply publishes here.
Related: Node:ffi in Node.js 26.9: how to call a C library without compiling a native addon