npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

exact-poly

v0.3.0

Published

Integer polygon geometry library (Rust/WASM) — exact arithmetic, no float errors

Readme

exact-poly

build

Live demo: exact-poly.merca.earth

Integer polygon geometry for deterministic on-chain validation. Rust library compiled to WebAssembly.

Used by

All arithmetic uses i64 coordinates in fixed-point representation (1 unit = 1 micrometer at SCALE = 1,000,000). No floats anywhere — results are bit-exact and reproducible across every platform.

Why

Floating-point polygon math is nondeterministic across architectures. On-chain land registry needs geometry operations that produce identical results on every validator node, in every browser, and in every Move VM execution. exact-poly solves this by using integer-only arithmetic with 128-bit intermediates where needed.

Features

Convex decomposition — split any simple polygon into convex parts:

  • Cascade strategy: tries ExactPartition → Bayazit → EarClip+Hertel-Mehlhorn, picks the first valid result
  • Ring rotation for difficult geometries
  • Minimize-parts mode: exhaustive search across all strategies and rotations
  • Steiner point tracking

Area & perimeter — exact computation without division:

  • twice_area returns 2× the area (avoids the ÷2 that would lose precision)
  • Signed area for winding detection
  • L1 (Manhattan) perimeter
  • Area conservation verification across decomposed parts

Ring operations:

  • CCW/CW winding detection and normalization
  • Simplicity check (self-intersection detection)
  • Convexity check
  • Collinear vertex removal
  • Canonical normalization (rotation to smallest vertex)

Spatial queries:

  • Point-in-convex-polygon (strict interior)
  • Point-on-boundary
  • Point-inside-or-on-boundary (inclusive)

Overlap detection:

  • SAT (Separating Axis Theorem) for convex pairs
  • AABB pre-filter for early rejection
  • Multi-part overlap search

Topology validation:

  • Shared edge detection between adjacent parts
  • BFS connectivity check
  • Hole detection via boundary graph analysis
  • Vertex-only contact detection
  • T-junction / partial overlap classification
  • Compactness (isoperimetric ratio) validation

Geometric primitives:

  • Cross product, orientation (CCW / CW / Collinear)
  • Point-on-segment, segment intersection
  • Reflex vertex detection

Install

npm (WASM)

npm install exact-poly

Package ships three wasm-bindgen targets — picked automatically via conditional exports:

| Runtime | Resolved entry | Notes | |---|---|---| | Node.js (import/require) | pkg/node/ | Sync init, works out of the box | | Bundlers (Vite, webpack, Rollup) | pkg/bundler/ | Vite needs vite-plugin-wasm + vite-plugin-top-level-await; webpack 5 supports WASM natively | | Browser direct (no bundler) | import "exact-poly/web" | Returns an init() you must await before calling exports |

All functions accept BigInt64Array for polygon rings encoded as flat [x0, y0, x1, y1, ...].

Node / bundler:

import { decompose_polygon, twice_area, is_convex } from "exact-poly";

const ring = BigInt64Array.from([0n, 0n, 60n, 0n, 60n, 40n, 30n, 40n, 30n, 80n, 0n, 80n]);

const result = decompose_polygon(ring, true);
console.log(result.parts.length); // convex parts

const area = twice_area(ring);
console.log(area); // "7200" (2× the actual area)

console.log(is_convex(ring)); // false (L-shape)

Browser direct:

import init, { twice_area } from "exact-poly/web";

await init();
const ring = BigInt64Array.from([0n, 0n, 60n, 0n, 60n, 40n, 30n, 40n, 30n, 80n, 0n, 80n]);
console.log(twice_area(ring)); // "7200"

Rust (crate)

[dependencies]
exact-poly = { git = "https://github.com/mercaearth/exact-poly" }
use exact_poly::decompose::decompose;
use exact_poly::types::{DecomposeOptions, ProtocolConfig};

let ring = vec![[0, 0], [60, 0], [60, 40], [30, 40], [30, 80], [0, 80]];
let result = decompose(&ring, &DecomposeOptions::default(), &ProtocolConfig::default()).unwrap();
println!("{} parts", result.parts.len());

Build

Requires wasm-pack:

bash build.sh

Builds three wasm-bindgen targets in parallel — pkg/bundler/, pkg/node/, pkg/web/. Run tests with:

cargo test

222 tests covering decomposition strategies, area conservation, topology validation, edge cases, and geometric primitives.

Demo

Interactive demo app with 7 tabs visualizing every feature:

cd demo && npm install && npm run dev

Draw polygons or pick presets. See decomposition results, area metrics, reflex vertices, point-in-polygon testing, SAT overlap detection, topology validation, and primitive operations — all running the WASM module in the browser.

Coordinate convention

| Property | Value | |---|---| | Type | i64 (signed 64-bit integer) | | Scale | 1,000,000 units = 1 meter | | Winding | Counter-clockwise (CCW) | | Encoding | Flat array: [x0, y0, x1, y1, ...] | | JS type | BigInt64Array |

Areas are returned as 2 × area (string-encoded u128 / i128) to avoid precision loss from division.

Protocol config

Validation functions accept an optional ProtocolConfig controlling on-chain limits:

| Parameter | Default (Merca) | Description | |---|---|---| | max_parts | 10 | Maximum convex parts per polygon | | max_vertices_per_part | 64 | Maximum vertices per convex part | | min_edge_length_squared | 10^12 | Minimum edge length² (1 meter²) | | min_compactness_ppm | 150,000 | Isoperimetric ratio floor (ppm) | | area_divisor | 2 × 10^12 | Converts 2×area to display m² |

Use ProtocolConfig::permissive() (Rust) or omit the config parameter (JS) for demo/testing with no validation limits.

API reference

Decomposition

| Function | Description | |---|---| | decompose_polygon(ring, allow_steiner, trace?, minimize?, config?) | Cascade decomposition into convex parts | | bayazit_decompose_polygon(ring, allow_steiner) | Bayazit algorithm only | | exact_vertex_partition_polygon(ring) | Diagonal-only partition (no Steiner points) | | ear_clip_triangulate_polygon(ring) | Ear clipping triangulation | | optimize_partition(parts) | Hertel-Mehlhorn merge of triangulated parts |

Area & metrics

| Function | Returns | |---|---| | twice_area_ring(ring) | Unsigned 2×area as string | | signed_area_2x_ring(ring) | Signed 2×area (positive = CCW) | | areas_conserved_values(original, part_areas) | true if sum of parts equals original | | perimeter_l1_ring(ring) | Manhattan perimeter as string |

Ring operations

| Function | Description | |---|---| | is_ccw_ring(ring) | Winding direction check | | ensure_ccw_ring(ring) | Reverse if CW → return CCW | | is_simple_ring(ring) | No self-intersections | | is_convex_ring(ring) | All vertices convex | | remove_collinear_ring(ring) | Strip collinear vertices | | normalize_polygon_ring(ring) | Canonical form (rotate to smallest vertex) |

Spatial queries

| Function | Description | |---|---| | point_strictly_inside_convex_ring(px, py, ring) | Strict interior (convex only) | | point_on_polygon_boundary_ring(px, py, ring) | On any edge | | point_inside_or_on_boundary_ring(px, py, ring) | Interior or boundary | | point_inside_any_part(parts, x, y) | Point in any convex part | | contains_polygon(outer_parts, inner_parts) | Full polygon containment |

Overlap

| Function | Description | |---|---| | sat_overlap(a, b) | SAT overlap for two convex polygons | | sat_overlap_with_aabb(a, b) | SAT with AABB early-out | | convex_parts_overlap(a, b) | Interior overlap (touching OK) | | parts_overlap(a_parts, b_parts) | Any part pair overlaps |

Topology

| Function | Description | |---|---| | validate_multipart_topology(parts, allow_vertex_contact?, config?) | Full topology validation | | has_exact_shared_edge(a, b) | Shared edge between two parts | | classify_contact(a, b) | "shared_edge" / "partial_contact" / "none" | | validate_decomposition(ring, parts, config?) | End-to-end on-chain validation |

Primitives

| Function | Description | |---|---| | orientation(ax, ay, bx, by, cx, cy) | "CounterClockwise" / "Clockwise" / "Collinear" | | cross2d(ax, ay, bx, by, cx, cy) | Cross product as string | | is_left(ax, ay, bx, by, px, py) | Point left of directed line | | is_reflex(prev_x, prev_y, curr_x, curr_y, next_x, next_y) | Reflex vertex test | | segments_intersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) | Segment intersection (including endpoints) | | segments_properly_intersect(...) | Strict crossing (excluding endpoints) | | point_on_segment(px, py, ax, ay, bx, by) | Point lies on segment |

Architecture

src/
  lib.rs              WASM bindings (#[wasm_bindgen] exports)
  types.rs            Core types: Point, Part, DecomposeResult, ProtocolConfig
  constants.rs        On-chain protocol constants
  decompose.rs        Cascade decomposition engine
  exact_partition.rs  Diagonal-only convex partition
  bayazit.rs          Bayazit convex decomposition
  ear_clip.rs         Ear clipping triangulation
  hertel_mehlhorn.rs  Triangle merge optimization
  area.rs             Exact area computation (i128)
  ring.rs             Ring operations (CCW, simple, normalize)
  spatial.rs          Point-in-polygon queries
  sat.rs              Separating Axis Theorem
  aabb.rs             Axis-aligned bounding boxes
  overlap.rs          Multi-part overlap detection
  containment.rs      Polygon containment
  shared_edge.rs      Edge sharing and contact classification
  topology.rs         Multipart topology validation
  validation.rs       Per-part structural validation
  validate_onchain.rs End-to-end on-chain validation
  primitives.rs       Cross product, orientation, segment ops
  signed.rs           Signed integer helpers (i128)

License

MIT — see LICENSE.