{"id":13534283,"url":"https://github.com/mapbox/earcut","last_synced_at":"2026-07-01T16:01:03.915Z","repository":{"id":25912140,"uuid":"29352975","full_name":"mapbox/earcut","owner":"mapbox","description":"The fastest and smallest JavaScript polygon triangulation library for your WebGL apps","archived":false,"fork":false,"pushed_at":"2026-06-25T15:26:41.000Z","size":814,"stargazers_count":2464,"open_issues_count":23,"forks_count":219,"subscribers_count":167,"default_branch":"main","last_synced_at":"2026-06-25T17:07:53.328Z","etag":null,"topics":["algorithm","computational-geometry","javascript","polygon","tessellation","triangulation"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mapbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2015-01-16T15:00:29.000Z","updated_at":"2026-06-25T15:12:04.000Z","dependencies_parsed_at":"2024-11-25T16:04:08.789Z","dependency_job_id":"b4c127aa-975b-4410-97f2-87accaa196f7","html_url":"https://github.com/mapbox/earcut","commit_stats":{"total_commits":240,"total_committers":17,"mean_commits":"14.117647058823529","dds":0.09166666666666667,"last_synced_commit":"32493e1686d4d988b07812bbecad8a1f92014ef1"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"purl":"pkg:github/mapbox/earcut","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fearcut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fearcut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fearcut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fearcut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mapbox","download_url":"https://codeload.github.com/mapbox/earcut/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fearcut/sbom","scorecard":{"id":616420,"data":{"date":"2025-08-11","repo":{"name":"github.com/mapbox/earcut","commit":"1b942f01f4093afe8f9ba729c3850b229f69eb12"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.7,"checks":[{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/node.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":4,"reason":"4 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 4","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":3,"reason":"Found 9/23 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.yml:8: update your workflow using https://app.stepsecurity.io/secureworkflow/mapbox/earcut/node.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/mapbox/earcut/node.yml/main?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: ISC License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":5,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Warn: 'branch protection settings apply to administrators' is disabled on branch 'main'","Warn: 'stale review dismissal' is disabled on branch 'main'","Warn: required approving review count is 1 on branch 'main'","Warn: codeowners review is not required on branch 'main'","Warn: 'last push approval' is disabled on branch 'main'","Warn: no status checks found to merge onto branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/mapbox/.github/SECURITY.md:1","Info: Found linked content: github.com/mapbox/.github/SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/mapbox/.github/SECURITY.md:1","Info: Found text in security policy: github.com/mapbox/.github/SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-xffm-g5w8-qvg7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":6,"reason":"SAST tool is not run on all commits -- score normalized to 6","details":["Warn: 11 commits out of 17 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T04:08:02.786Z","repository_id":25912140,"created_at":"2025-08-21T04:08:02.786Z","updated_at":"2025-08-21T04:08:02.786Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34915002,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithm","computational-geometry","javascript","polygon","tessellation","triangulation"],"created_at":"2024-08-01T07:01:29.565Z","updated_at":"2026-07-01T16:01:03.904Z","avatar_url":"https://github.com/mapbox.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","\u003e 1K ⭐️","Libraries"],"sub_categories":["JavaScript"],"readme":"# Earcut\n\nThe fastest and smallest JavaScript **polygon triangulation** library. 4KB gzipped.\n[![Node](https://github.com/mapbox/earcut/actions/workflows/node.yml/badge.svg)](https://github.com/mapbox/earcut/actions/workflows/node.yml)\n[![](https://img.shields.io/badge/simply-awesome-brightgreen.svg)](https://github.com/mourner/projects)\n\n![Earcut triangulation example](earcut.png)\n\nEarcut is designed to be fast enough for real-time [triangulation](https://en.wikipedia.org/wiki/Polygon_triangulation) in the browser,\nfavoring raw speed and simplicity over triangulation quality,\nwhile being robust enough to handle most practical datasets without crashing or producing garbage,\nwith an option to refine the result to [Delaunay](https://en.wikipedia.org/wiki/Delaunay_triangulation) quality at a small cost.\nOriginally built for [Mapbox GL JS](https://www.mapbox.com/mapbox-gljs) (WebGL-based interactive maps),\nit's now also used by [Three.js](https://threejs.org/) and many other projects.\n\n## [Demo](https://mapbox.github.io/earcut/viz/)\n\n## Usage\n\n```js\nimport earcut from 'earcut';\nconst triangles = earcut([10,0, 0,50, 60,60, 70,10]); // returns [1,0,3, 3,2,1]\n```\n\n## Algorithm\n\nThe library implements a modified ear slicing algorithm,\noptimized by [z-order curve](http://en.wikipedia.org/wiki/Z-order_curve) and spatial hashing\nand extended to handle holes, twisted polygons, degeneracies and self-intersections\nin a way that doesn't _guarantee_ correctness of triangulation,\nbut attempts to always produce acceptable results for practical data.\n\nIt's based on ideas from\n[FIST: Fast Industrial-Strength Triangulation of Polygons](http://www.cosy.sbg.ac.at/~held/projects/triang/triang.html) by Martin Held\nand [Triangulation by Ear Clipping](http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf) by David Eberly.\n\n## Performance\n\nEarcut is heavily optimized for its primary workload — triangulating polygons from\n[Mapbox Vector Tiles](https://github.com/mapbox/vector-tile-spec). On a representative\nbenchmark of **119,680 real-world polygons** (1.9M vertices) drawn from a window of map tiles\nthrough zooms 4–16, it triangulates the whole set in **~445 ms** on a Macbook Pro M1 Pro (2021),\nwith optional Delaunay refinement taking additional **~222 ms**.\nYou can run the benchmark yourself with `npm run bench`.\n\n## Robustness\n\nEarcut does **not** guarantee a correct triangulation on arbitrary input — it trades quality\nfor speed, aiming to always produce an acceptable result on practical data without crashing or\nemitting garbage. The input is assumed to be a valid polygon: rings that don't self-cross or\noverlap, holes that stay inside the outer ring, and no duplicate or zero-length edges. On input\nthat breaks these assumptions, the result can be noticeably wrong — overlapping triangles, gaps,\nor triangles outside the polygon. If correctness matters, clean your input first; for a\nguaranteed-correct triangulation even on bad data, see\n[libtess.js](https://github.com/brendankenny/libtess.js) (slower and larger).\n\nThe output is also not _conforming_ — a vertex may land in the middle of another triangle's edge\n(a T-junction). This is harmless for rendering but can break navmesh or FEM use; if you need a\nconforming mesh, [remove T-junctions in a post-process](https://github.com/mapbox/earcut/issues/74#issuecomment-4826113682).\n\n## Install\n\nInstall with NPM: `npm install earcut`, then import as a module:\n\n```js\nimport earcut, {flatten, deviation, refine} from 'earcut';\n```\n\nOr use as a module directly in the browser with [jsDelivr](https://www.jsdelivr.com/esm):\n\n```html\n\u003cscript type=\"module\"\u003e\n    import earcut from 'https://cdn.jsdelivr.net/npm/earcut/+esm';\n\u003c/script\u003e\n```\n\nAlternatively, there's a UMD browser bundle with an `earcut` global variable (exposing the main function as `earcut.default`):\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/earcut/dist/earcut.min.js\"\u003e\u003c/script\u003e\n```\n\n## API\n\n### `earcut(vertices[, holes, dimensions = 2])`\n\n* `vertices` is a flat array of vertex coordinates like `[x0,y0, x1,y1, x2,y2, ...]`.\n* `holes` is an array of hole _indices_ if any\n  (e.g. `[5, 8]` for a 12-vertex input would mean one hole with vertices 5\u0026ndash;7 and another with 8\u0026ndash;11).\n* `dimensions` is the number of coordinates per vertex in the input array (`2` by default). Earcut is a **2D** algorithm: only `x` and `y` are used for triangulation, and any extra coordinates are ignored (3D data is treated as projected onto the XY plane).\n\nEach group of three vertex indices in the resulting array forms a triangle.\n\n```js\n// triangulating a polygon with a hole\nearcut([0,0, 100,0, 100,100, 0,100,  20,20, 80,20, 80,80, 20,80], [4]);\n// [3,0,4, 5,4,0, 3,4,7, 5,0,1, 2,3,7, 6,5,1, 2,7,6, 6,1,2]\n\n// triangulating a polygon with 3d coords\nearcut([10,0,1, 0,50,2, 60,60,3, 70,10,4], null, 3);\n// [1,0,3, 3,2,1]\n```\n\nIf you pass a single vertex as a hole, Earcut treats it as a Steiner point.\n\nOutput triangles always have a consistent **winding order** regardless of the input polygon's winding \u0026mdash; counter-clockwise in a y-up coordinate system (clockwise in y-down/screen space). If you need the opposite orientation (e.g. for back-face culling or normals in 3D), call `.reverse()` on the result.\n\n### `refine(triangles, vertices[, dimensions = 2])`\n\nIf triangle quality matters, you can run an optional refinement pass after triangulation:\n\n```js\nconst triangles = earcut(vertices, holes, dimensions);\nrefine(triangles, vertices, dimensions);\n```\n\nThis mutates `triangles` in place, legalizing interior edges with Delaunay flips while preserving\nthe polygon boundary and holes. It keeps the same number of triangles and the same index format,\nbut usually removes many skinny triangles and reduces total triangle edge length.\n\nRefinement is a post-process, so it doesn't affect the speed of normal `earcut` calls unless you\nexplicitly call it. It assumes a valid manifold triangulation, such as the output of `earcut`, and\ndoesn't repair invalid polygon input or make the mesh conforming.\n\n### `flatten(data)`\n\nIf your input is a multi-dimensional array (e.g. [GeoJSON Polygon](http://geojson.org/geojson-spec.html#polygon)),\nyou can convert it to the format expected by Earcut with `flatten`:\n\n```js\nconst data = flatten(geojson.geometry.coordinates);\nconst triangles = earcut(data.vertices, data.holes, data.dimensions);\n```\n\n### `deviation(vertices, holes, dimensions, triangles)`\n\nAfter getting a triangulation, you can verify its correctness with `deviation`:\n\n```js\nconst d = deviation(vertices, holes, dimensions, triangles);\n```\n\nReturns the relative difference between the total area of triangles and the area of the input polygon.\n`0` means the triangulation is fully correct.\n\n## Ports to other languages\n\n- [mapbox/earcut.hpp](https://github.com/mapbox/earcut.hpp) (C++11)\n- [JaffaKetchup/dart_earcut](https://github.com/JaffaKetchup/dart_earcut) (Dart)\n- [earcut4j/earcut4j](https://github.com/earcut4j/earcut4j) (Java)\n- [Larpon/earcut](https://github.com/Larpon/earcut) (V)\n- [measuredweighed/SwiftEarcut](https://github.com/measuredweighed/SwiftEarcut) (Swift)\n- [goswinr/Earcut](https://github.com/goswinr/Earcut/)(F# / .NET)\n- [tenyoru/earcut.zig](https://github.com/tenyoru/earcut.zig) (Zig)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmapbox%2Fearcut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmapbox%2Fearcut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmapbox%2Fearcut/lists"}