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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@thi.ng/geom

v8.3.9

Published

Functional, polymorphic API for 2D geometry types & SVG generation

Readme

@thi.ng/geom

npm version npm downloads Mastodon Follow

[!NOTE] This is one of 211 standalone projects, maintained as part of the @thi.ng/umbrella monorepo and anti-framework.

🚀 Please help me to work full-time on these projects by sponsoring me on GitHub. Thank you! ❤️

For the Clojure version, please visit: thi.ng/geom-clj

About

Functional, polymorphic API for 2D geometry types & SVG generation.

This project is a partially ported from the Clojure version of the same name. All polymorphic operations built on @thi.ng/defmulti.

Shape types

The following 2D/3D shape primitives are provided. All these types are implemented as basic data container classes with additional eponymous factory functions (e.g. Circle (class) => circle() (function)), which are encouraged to be used instead of calling class constructors directly. For many shapes there're multiple ways to create them, please also check linked sources and/or docs.

[!IMPORTANT] Support for 3D shapes is WIP and currently limited to the various operations provided by this package, but does not yet find any usage outside (e.g. for visualization). Sill, even the ops supported so far can be useful for many use cases...

| Shape/Form | Description | Hiccup support | |--------------------------------------------------------------------------------------------------------|---------------------------------------|---------------------| | AABB | 3D Axis-aligned bounding box | ✅(1) | | Arc | 2D elliptic arc | ✅ | | BPatch | 2D cubic bezier patch (4x4 points) | ✅ | | Circle | 2D circle | ✅ | | ComplexPolygon | 2D polygon w/ holes | ✅ | | Cubic | 2D cubic bezier | ✅ | | Cubic3 | 3D cubic bezier | ✅(1) | | Ellipse | 2D ellipse | ✅ | | Extra | Custom embedded hiccup/SVG data | ✅ | | Group | group of 2D shapes | ✅ | | Group3 | group of 3D shapes | ✅(1) | | Line | 2D line segment | ✅ | | Line3 | 3D line segment | ✅(1) | | Path | 2D path (w/ optional holes/sub-paths) | ✅ | | Path3 | 3D path (w/ optional holes/sub-paths) | ✅(1),(2) | | Plane | 3D plane | ✅(1) | | Points | 2D point cloud | ✅ | | Points3 | 3D point cloud | ✅(1) | | Polygon | 2D simple polygon (no holes) | ✅ | | Polygon3 | 3D simple polygon (no holes) | ✅ | | Polyline | 2D polyline | ✅ | | Polyline3 | 3D polyline | ✅(1) | | Quad | 2D quad (4-gon) | ✅ | | Quad3 | 2D quad (4-gon) | ✅(1) | | Quadratic | 2D quadratic bezier | ✅ | | Quadratic3 | 3D quadratic bezier | ✅(1) | | Ray | 2D ray | ✅ | | Ray3 | 3D ray | ✅(1) | | Rectangle | 2D rectangle | ✅ | | Sphere | 3D sphere | ✅(1) | | Text | Basic stub for text labels | ✅(3) | | Triangle | 2D triangle | ✅ | | Triangle3 | 3D triangle | ✅(1) |

  • (1) valid hiccup format, but currently still missing external tool/library support
  • (2) only lines, cubic & quadratic curve segments supported
  • (3) merely treated as a point in space (e.g. used for placing text labels), no geometry of text itself

Hiccup support

[!NOTE] Sidebar with background information for advanced usage only. Most users can safely ignore this.

With very few exceptions these all are implementing the IToHiccup interface and so can be easily converted (via hiccup) to a variety of other formats, incl. conversion to SVG.

By design, for more flexibility and for performance reasons, the hiccup flavor used by this package is not compatible with that used by thi.ng/hiccup-svg, though the latter provides a convertTree() function for that purpose. This is only needed for some cases of dynamic in-browser SVG DOM creation...

Instead, the hiccup format used here for interim interop is compatible with that used by the thi.ng/hiccup-canvas package (see its readme for details) and avoids extraneous stringification of geometry data and attrib values. A brief example to illustrate some differences:

import { circle, asSvg } from "@thi.ng/geom";
import { convertTree } from "@thi.ng/hiccup-svg";

// a circle with RGBA color attrib
const a = circle([100, 200], 300, { fill: [1, 0.5, 0, 1] });

// invocation of the IToHiccup interface (all shapes support it)
console.log(a.toHiccup());
// [ "circle", { fill: [ 1, 0, 0, 1 ] }, [ 100, 200 ], 300 ]

// convert shape into to a SVG compatible hiccup format
// (i.e. stringify attributes, convert colors etc.)
console.log(convertTree(a));
// [ "circle", { fill: "#ff8000", cx: "100", cy: "200", r: "300" } ]

// asSvg() automatically uses convertTree() when serializing shape(s) to SVG
console.log(asSvg(a));
// <circle fill="#ff8000" cx="100" cy="200" r="300"/>

SVG support

For 2D shape types only, SVG conversion is included via the asSvg() and svgDoc() functions.

Polymorphic operations

The following operations are provided (many also applicable to shape groups directly and/or perform automatic resampling/conversion if needed).

| Operation | Description | |-----------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| | applyTransforms() | applies any spatial transformation attributes | | arcLength() | compute arc length / perimeter of shape boundary | | area() | signed/unsigned surface area | | asCubic() | convert shape boundary to cubic bezier segments | | asPath() | convert shape to path | | asPolygon() | convert shape to polygon(s) | | asPolyline() | convert shape to polyline(s) | | asSector() | convert arc to sector (path) | | asSvg() | serialize shape/group/hierarchy to SVG | | bounds() | compute bounding box | | center() | center shape around origin or point | | centroid() | compute shape centroid | | classifyPoint() | classify point in relation to shape boundary (in/out) | | clipConvex() | clip shape against convex boundary | | closestPoint() | compute closest point on shape boundary | | convexHull() | compute convex hull (2d only) | | convolve() | kernel based vertex convolution/filtering | | edges() | extract edges | | edgesFromTessellation() | extract unique edges from tessellation results | | fitIntoBounds2() | rescale/reposition a 2D shape into a destination boundary | | fitIntoBounds3() | rescale/reposition a 3D shape into a destination boundary | | fitAllIntoBounds2() | rescale/reposition multiple 2D shapes into a boundary | | flip() | reverse order (vertices or direction) | | graphFromTessellation() | create graph from tessellation results | | intersects() | pairwise shape intersection (various types) | | mapPoint() | transform world space point into local shape UV space | | offset() | shape/path offsetting | | pointAt() | compute point on shape boundary at parametric position | | pointInside() | check if point is inside shape | | proximity() | distance from point to shape boundary | | resample() | resample/convert shape | | rotate() | rotate shape (2D only) | | rotateAroundAxis() | rotate shape (3D only) | | rotateX() | rotate shape (3D only) | | rotateY() | rotate shape (3D only) | | rotateZ() | rotate shape (3D only) | | scale() | scale shape (uniformly/non-uniformly) | | scaleWithCenter() | scale shape with pivot point | | scatter() | create random points inside a shape boundary | | simplify() | simplify shape/boundary (Douglas-Peucker) | | splitArcLength() | split shapes & groups based on max. arc length | | splitAt() | split shape/boundary at parametric position | | splitNearPoint() | split shape/boundary near world position | | subdivCurve() | recursively apply curve subdivision kernel | | tangentAt() | compute tangent at parametric position | | tessellate() | (recursively) tessellate shape | | transformVertices() | apply custom function to each vertex | | transform() | apply transformation matrix | | translate() | translate shape | | union() | compute shape union | | unmapPoint() | transform local shape UV point into world space | | vertices() | extract/sample vertices from shape boundary | | volume() | compute shape volume (3D only) | | warpPoint() | transfer single point between the local spaces defined by 2 shapes | | warpPoints() | transfer points between the local spaces defined by 2 shapes | | warpPointsBPatch() | transfer points to the local spaces of a bezier patch | | withAttribs() | shallow copy of given shape with new attribs assigned |

Shape factory functions

In addition to the above listed direct shape type functions, the following additional shape creation helpers are provided:

AABB

Arc

Bezier patch

Circle

Cubic

Group

Line

Path

Plane

Polygon

Polyline

Quad

Rect

Sphere

Triangle

Constants & presets

Some of the shape operations require configuration with specific algorithms and/or constants. In all cases this relies on a completely extensible mechanism, but the package provides presets for common options/implementations:

Curve subdivision kernels

To be used with subdivideCurve():

Polygon tessellation algorithms

To be used with tessellate():

See thi.ng/geom-tessellate readme for diagrams/illustrations of each algorithm!

Tessellation behaviors:

Tessellation post-processing:

Vertex convolution kernels

To be used with convolve():


This package acts as a higher-level frontend for most of the following related packages (which are more low-level, lightweight and usable by themselves too):

Support packages

Related packages

Status

STABLE - used in production

Search or submit any issues for this package

Installation

yarn add @thi.ng/geom

ESM import:

import * as geom from "@thi.ng/geom";

Browser ESM import:

<script type="module" src="https://esm.run/@thi.ng/geom"></script>

JSDelivr documentation

For Node.js REPL:

const geom = await import("@thi.ng/geom");

Package sizes (brotli'd, pre-treeshake): ESM: 17.50 KB

Dependencies

Note: @thi.ng/api is in most cases a type-only import (not used at runtime)

Usage examples

39 projects in this repo's /examples directory are using this package:

| Screenshot | Description | Live demo | Source | |:------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------|:-------------------------------------------------------------|:------------------------------------------------------------------------------------------| | | Basic 2D boid simulation and spatial indexing neighbor lookups | Demo | Source | | | Self-modifying, animated typographic grid with emergent complex patterns | Demo | Source | | | Fiber-based cooperative multitasking basics | Demo | Source | | | Polygon point classification (inside/boundary/outside) | Demo | Source | | | Shape conversions & operations using polygons with holes | Demo | Source | | | Convex hull & shape clipping of 2D polygons | Demo | Source | | | Piechart visualization of CSV data | Demo | Source | | | Embedding thi.ng/hiccup data/elements in thi.ng/geom shape hierarchies | Demo | Source | | | geom-fuzz basic shape & fill examples | Demo | Source | | | Hex grid generation & tessellations | Demo | Source | | | (Re)Constructing the thi.ng logo using a 2D signed-distance field | Demo | Source | | | SVG path to SDF, applying deformation and converting back to SVG | Demo | Source | | | 2.5D hidden line visualization of digital elevation files (DEM) | Demo | Source | | | Animated, recursive polygon tessellations | Demo | Source | | | Iterating the unique edges of a tessellation | Demo | Source | | | Poisson-disk shape-aware sampling, Voronoi & Minimum Spanning Tree visualization | Demo | Source | | | Augmenting thi.ng/geom shapes for WebGL, using instancing & attribute buffers | Demo | Source | | | Converting thi.ng/geom shape types for WebGL | Demo | Source | | | Mouse gesture / stroke analysis, simplification, corner detection | Demo | Source | | | 2D Bezier curve-guided particle system | Demo | Source | | | Animated arcs & drawing using hiccup-canvas | Demo | Source | | | Canvas based Immediate Mode GUI components | Demo | Source | | | Animated sine plasma effect visualized using contour lines | Demo | Source | | | k-means clustering visualization | Demo | Source | | | Live coding playground for 2D geometry generation using @thi.ng/pointfree-lang | Demo | Source | | | 2D Poisson-disc sampler with procedural gradient map | Demo | Source | | | Polygon to cubic curve conversion & visualization | Demo | Source | | | Animated, iterative polygon subdivisions & visualization | Demo | Source | | | Quasi-random lattice generator | Demo | Source | | | Minimal rdom-canvas animation | Demo | Source | | | Animated Voronoi diagram, cubic splines & SVG download | Demo | Source | | | 2D scenegraph & shape picking | Demo | Source | | | 2D scenegraph & image map based geometry manipulation | Demo | Source | | | Basic 2D scenegraph example with pan/zoom functionality | Demo | Source | | | Compute cubic spline position & tangent using Dual Numbers | Demo | Source | | | SVG path parsing & dynamic resampling | Demo | Source | | | 3D wireframe textmode demo | Demo | Source | | | Multi-layer vectorization & dithering of bitmap images | Demo | Source | | | Animated t-SNE visualization of 4D data | Demo | Source |

API

Generated API docs

Authors

If this project contributes to an academic publication, please cite it as:

@misc{thing-geom,
  title = "@thi.ng/geom",
  author = "Karsten Schmidt",
  note = "https://thi.ng/geom",
  year = 2013
}

License

© 2013 - 2025 Karsten Schmidt // Apache License 2.0