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

@jolars/eunoia

v1.9.0

Published

Area-proportional Euler and Venn diagrams

Readme

@jolars/eunoia

npm version Build and Test License: MIT OR Apache-2.0

Area-proportional Euler and Venn diagrams for JavaScript — the WebAssembly build of the Rust eunoia engine. Give it a set of sizes and intersections and it fits a layout of shapes whose areas match your data as closely as possible, then hands back plain JavaScript objects — circles, ellipses, polygons, or per-region pieces — that you draw however you like (SVG, Canvas, D3).

Install

npm install @jolars/eunoia

The default entry is an ES module backed by WebAssembly, so it needs a bundler that understands an import-ed .wasm module (Vite, webpack 5, Rollup, esbuild, …) and Node 20+. It ships its own TypeScript types — no @types package needed. For bundler-less environments, see Entry points.

Usage

import { euler, venn } from "@jolars/eunoia";

// Fit an Euler diagram from set sizes.
const layout = euler({
  sets: { A: 5, B: 2, "A&B": 1 },
  shape: "circle", // "circle" | "ellipse" | "square" | "rectangle"
  output: "shapes", // "shapes" | "polygons" | "regions"
  inputType: "exclusive", // "exclusive" | "inclusive"
  seed: 42,
});

if (layout.mode === "shapes" && layout.shape === "circle") {
  for (const c of layout.circles) {
    console.log(c.label, c.x, c.y, c.radius);
  }
}

// Or build a canonical n-set Venn diagram (ignores set sizes).
const v = venn({ n: 3, output: "regions" });

sets is keyed by combination expression — a single set ("A") or sets joined with & ("A&B"). Values are exclusive sizes by default; pass inputType: "inclusive" if your numbers are full set unions instead.

The output option decides the result shape: "shapes" returns primitive parameters (circles / ellipses / squares / rectangles), "polygons" adds one closed outline per set, and "regions" returns the exclusive pieces (A only, A&B, …) for per-region fills and label placement. Every mode also carries fit metrics. See the JavaScript quickstart for the full walkthrough.

Entry points

All three ship from the one package:

| Import | What it is | | --------------------- | ------------------------------------------------------------------------------------- | | @jolars/eunoia | Default. Bundler-friendly; imports the .wasm module directly. Use with a bundler. | | @jolars/eunoia/web | Bundler-less. A single ESM file with the wasm inlined; await init() once before use. | | @jolars/eunoia/svg | Pure JavaScript (no wasm). Turns a Layout into an SVG string. Works from a CDN. |

Browser / Observable (no bundler)

The default entry imports the .wasm module directly, which only a bundler can resolve. For a plain HTML page, an Observable notebook, or any environment without a build step, use @jolars/eunoia/web — a single self-contained ESM file with the WebAssembly inlined. Call init() once before fitting:

<script type="module">
  import { euler, init } from "https://esm.sh/@jolars/eunoia/web";

  await init(); // instantiate the embedded wasm once; idempotent

  const layout = euler({ sets: { A: 5, B: 2, "A&B": 1 } });
  console.log(layout.circles);
</script>

In Observable:

eunoia = import("https://esm.sh/@jolars/eunoia/web")
await eunoia.init()
layout = eunoia.euler({ sets: { A: 5, B: 2, "A&B": 1 } })

@jolars/eunoia/svg is pure JavaScript (no WebAssembly), so it already works directly from a CDN and during server-side rendering with no init():

import { euler } from "@jolars/eunoia";
import { toSvg } from "@jolars/eunoia/svg";

const layout = euler({ sets: { A: 5, B: 2, "A&B": 1 }, output: "regions" });
document.body.innerHTML = toSvg(layout, { showLabels: true });

For interactivity, toSvg / svgBody can attach native hover tooltips and data-* hooks to each region and set shape via tooltip, interactive, and regionAttrs (each hook gets a RegionInfo of { combination, sets, area }):

const svg = toSvg(layout, {
  interactive: true, // data-combination + data-area on each fill
  tooltip: (r) => `${r.combination}: ${r.area.toFixed(0)}`,
});

Eunoia sees only set/intersection sizes, so combination -> members is yours to compute; format small lists in tooltip, or keep large ones JS-side and look them up on hover via data-combination to keep the SVG small.

Server-side rendering: call the wasm-backed euler / venn from the client (e.g. a dynamic import("@jolars/eunoia") inside onMount / useEffect) so the wasm module isn't instantiated during the server render. The ./svg entry has no such restriction.

Documentation

Full field-level types ship with the package; your editor's "go to definition" / IntelliSense will surface them.

License

Distributed under the terms of either the MIT license or the Apache License 2.0, at your option.