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

@gcu/bearing

v0.2.3

Published

Structural geology stereonet library — projections, statistics, contouring, fabric analysis

Readme

bearing.js

GCU: WA DOI License: MIT

Structural geology stereonet library in pure JavaScript. No dependencies.

Live demo

Features

  • Equal-area (Schmidt) and equal-angle (Wulff) projections
  • Planes, poles, lines, great circles, small circles
  • Kernel-density contouring — Fisher kernel (multiples-of-uniform-density) or Kamb (1959) counting (σ)
  • Eigenvalue decomposition, Woodcock and Vollmer fabric parameters, Bingham statistics
  • Confidence regions: Fisher cone of confidence + eigenvector confidence ellipses
  • Hypothesis tests: spherical uniformity (Bingham), two-sample common mean (Watson–Williams), Rayleigh
  • Bootstrap confidence regions (non-parametric cone for the mean, ellipse for eigenvectors)
  • Structural analysis: π/fold-axis (best-fit great circle), best-fit plane, unfolding/tilt test
  • Mobile compass math: device orientation → dip-direction/dip and trend/plunge
  • Fault-slip & paleostress: kinematic P/T axes, right-dihedra field, Michael (1984) stress inversion
  • Set identification: axial k-means + soft Watson-mixture EM (BIC chooses the number of sets)
  • Fabric diagrams: Woodcock K–C, Vollmer P–G–R ternary
  • Synthetic sampling: Fisher draws, smoothed bootstrap, uniform + concentrated rotation sampling
  • Rotation analysis (SO(3)): quaternions, foliation∧lineation frames, misorientation, mean rotation
  • Rotation-notation conversions: 24 Euler conventions with per-axis sign flags; dip/dipdir/rake (Leapfrog, Isatis), Bunge, GSLIB presets
  • Attitude I/O: dip-direction/dip, strike/dip, quadrant notation
  • Rose diagrams (axial/directional binning, petal geometry, SVG output)
  • Arcball drag-rotation primitive (frame-consistent, no gimbal flip)
  • SVG rendering with no DOM dependencies; PNG export via canvas (toPNG)
  • Ships TypeScript declarations (bearing.d.ts) — no build step, source stays plain JS
  • ~34 KB minified, ~11 KB gzipped

Install

npm install

Usage

As an ES module:

import { Stereonet } from './src/index.js';

const sn = new Stereonet();
sn.plane(120, 45);
sn.pole(120, 45);

document.body.innerHTML = sn.svg();

As a bundled IIFE (browser global):

npm run build
<script src="bearing.js"></script>
<script>
  const sn = new bearing.Stereonet();
  sn.plane(120, 45);
  document.body.innerHTML = sn.svg();
</script>

API

| Module | Description | |--------|-------------| | Stereonet | Main class — add planes, poles, lines, contours, render to SVG | | conversions | Attitude conversions (dip-direction, strike, direction cosines) | | statistics | Eigenvalues, Fisher, Woodcock, Vollmer, Bingham, confidence cone/ellipse, uniformity & common-mean tests | | circular | Circular (azimuthal) statistics: mean, R, von Mises κ, Rayleigh test | | rose | Rose-diagram binning (roseBins), petal geometry (rosePetals), SVG (roseSVG) | | analysis | Fold axis / best-fit great circle, best-fit plane, dataset rotation & unfolding | | fault | Fault-slip kinematics: P/T axes, Angelier dihedra, Michael (1984) paleostress inversion | | cluster | Orientation-set identification: k-means + Watson-mixture EM with BIC model selection | | fabricplot | Fabric diagnostic diagrams: Woodcock K–C plot, Vollmer P–G–R ternary | | simulate | Fisher sampling + Fisher-kernel smoothed bootstrap (synthetic fabrics) | | compass | Device-orientation → attitude (planeFromDeviceOrientation, lineFromDeviceOrientation) | | color | Named colour scales + value→colour mapping (colorScale, sampleScale, mapValue) | | io | Parse attitude strings and text blocks | | equalArea / equalAngle | Projection functions | | vec3 / mat3 / quat | 3D vector, matrix, and quaternion operations | | rotation | SO(3): frames, misorientation, mean + bootstrap confidence, apply/compose, log/exp (rotation vector) | | euler | Rotation-notation conversions: 24 Euler conventions (± per-axis signs) ↔ matrix/quaternion; dip/dipdir/rake, Bunge, GSLIB presets | | curves | Small circles, great circles as point sequences | | computeContours | Kernel-density contour lines | | densityGrid | Fisher-kernel density raster (MUD), reusable for heatmaps | | SvgBuilder | Low-level SVG path/element builder |

Interactivity & overlays

Building an interactive viewer (cursor read-outs, click-to-pick, labels, heatmaps) on top of the engine? These methods cover the pixel ↔ attitude plumbing so you don't have to reach into internals.

const sn = new Stereonet({ size: 560 });
const el = sn.element();              // live DOM <svg>, updated in place by render()

// Pixel → attitude: cursor read-out / click-to-pick (null outside the net)
el.addEventListener('pointermove', e => {
  const pt = /* map clientX/Y to the SVG viewBox */;
  const dcos = sn.unproject(pt.x, pt.y);
  if (dcos) console.log(conversions.dcosToLine(dcos)); // [trend, plunge]
});

// Attitude → pixel: place a leader/label that tracks rotation
const { x, y, upper } = sn.projectLine(120, 35);  // upper === on the hidden hemisphere

// Anchored text label (hidden automatically when it rotates to the upper hemisphere)
sn.text(120, 35, 'B₁', { dx: 8, dy: -6, fill: '#b06f06' });

// Net geometry for your own overlays — no private fields needed
const { center, radius, scale, projR } = sn.layout;
// a projected point [px, py] is at SVG [center + px*scale, center - py*scale]

Density heatmap

heatmap() paints a filled Fisher-kernel raster beneath the grid; it mirrors contour() (call updateHeatmap() after changing rotation, clearHeatmap() to remove):

sn.heatmap(dcos, { gridSize: 48, color: t => `rgba(176,111,6,${t})` });
sn.contour(dcos, { levels: [2, 4, 6, 8] });   // line contours over the fill

For full control, compute the raster once with densityGrid() and feed it to both your own renderer and computeContours() (via options.grid) to avoid recomputing it:

import { densityGrid, computeContours } from './src/index.js';

const grid = densityGrid(dcos, { projection: 'equal-area', gridSize: 48 });
// grid → { grid: Float64Array, gridSize, step, projR, projection }; cells outside the net are NaN
const contours = computeContours(dcos, { levels: [2, 4, 6], grid });

Tests

npm test

470 tests using Node.js built-in test runner.

License

MIT

GCU Classification

WA — Works in an Airplane. Fully offline, single HTML file, zero network calls. Deployable on air-gapped mine site laptops, field camp tablets, or opened from a USB stick.