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

@autoremesher/wasm

v0.2.0

Published

Automatic quad remeshing (AutoRemesher) compiled to WebAssembly, with a TypeScript-first API for Three.js, glTF, OBJ, and raw buffers.

Readme

@autoremesher/wasm

Automatic quad remeshing in the browser and Node.js — powered by WebAssembly.

This project ports AutoRemesher (Jeremy Hu) to WebAssembly and wraps it in a small TypeScript-first API. Give it a triangle mesh; get back a quad-dominant mesh suitable for subdivision, look-dev, and further modeling.

npm install @autoremesher/wasm
import { remesh } from "@autoremesher/wasm";

const result = await remesh(
  { vertices, indices }, // Float32Array xyz + Uint32Array triangles
  { targetQuads: 2000 }
);

// result.quads     — 4 indices per face (true quads + rare tris)
// result.indices   — triangulated for GPU / Three.js
// result.vertices  — remeshed positions
// result.quality   — "remeshed" | "near-sealed"
// result.watertight

Status: 0.2.x — open-source beta. Works well on clean, closed organic meshes. Hard-surface, scans, and multi-part exports are improving; expect retries or errors on pathological topology. Use a Web Worker in the browser so the UI stays responsive.


Features

  • Quad-dominant remesh — native AutoRemesher / MIQ pipeline in WASM
  • TypeScript-first — full .d.ts types, ESM + CommonJS
  • Flexible inputs — raw buffers, OBJ text, GLB / glTF, or a Three.js BufferGeometry-like object
  • Self-contained — ~1.1 MB single-thread WASM (+ optional pthreads build), no native install
  • Browser + Node — same API; Node example included
  • UV re-projection — closest-point transfer when the input has UVs
  • Quality gates — topology checks, density scoring, safe hole fill, explicit quality / watertight on the result
  • Optional threads — pthreads binary for multi-island speedups (needs COOP/COEP in browsers)

Repository layout

This repository is the full open-source package:

.
├── src/              TypeScript API (source of truth)
├── lib/              Built ESM + CJS + types (published)
├── wasm/             Prebuilt .mjs + .wasm (st + mt)
├── emscripten/       Bindings, shims, build scripts
├── cpp/              Vendored AutoRemesher + third-party C++
├── test/             Node test suite
├── examples/
│   ├── node-remesh.mjs   CLI sample
│   └── web/              Browser playground (Vite + React + Three)
├── package.json      @autoremesher/wasm
└── README.md

Prebuilt lib/ and wasm/ are committed so consumers and CI can install without the Emscripten SDK. Rebuild with npm run build when you change C++ or TypeScript.

Installation

npm install @autoremesher/wasm

| Package | Role | | --- | --- | | @autoremesher/wasm | Core remesher (this package) | | meshoptimizer | Runtime dependency (input decimation helpers) | | three | Optional peer — only if you use @autoremesher/wasm/three |

Quick start

Raw buffers

import { remesh } from "@autoremesher/wasm";

const result = await remesh(
  {
    vertices: /* Float32Array length % 3 === 0 */,
    indices: /* Uint32Array length % 3 === 0 */,
  },
  {
    targetQuads: 2000,
    adaptivity: 0.5,
    onProgress: (p, status) => console.log(Math.round(p * 100), status),
  }
);

console.log(result.quadCount, result.quality, result.watertight);

Three.js

import { remesh } from "@autoremesher/wasm";
import { fromBufferGeometry, toBufferGeometry } from "@autoremesher/wasm/three";

const result = await remesh(fromBufferGeometry(sourceGeometry), {
  targetQuads: 4000,
  adaptivity: 0.8,
});
mesh.geometry = toBufferGeometry(result);

You can also pass a BufferGeometry (or any object with the same shape) straight to remesh(). The core package never imports three.

OBJ

import { remesh, resultToObj } from "@autoremesher/wasm";

const objText = await fetch("model.obj").then((r) => r.text());
const result = await remesh(objText, { targetQuads: 3000 });
const out = resultToObj(result); // native quad faces in OBJ

GLB / glTF

import { remesh } from "@autoremesher/wasm";

const glb = await fetch("model.glb").then((r) => r.arrayBuffer());
const result = await remesh(glb, { targetQuads: 5000 });

Triangle primitives are merged before remeshing. External .bin URIs are not fetched — use GLB or embedded / data-URI buffers.

Node.js

import { remesh, resultToObj } from "@autoremesher/wasm";
import { readFile, writeFile } from "node:fs/promises";

const result = await remesh(await readFile("input.obj", "utf8"), {
  targetQuads: 2000,
  onProgress: (p, status) => console.log(`${(p * 100) | 0}% ${status}`),
});
await writeFile("output.obj", resultToObj(result));

See examples/node-remesh.mjs.

Options

| Option | Type | Default | Description | | --- | --- | --- | --- | | targetQuads | number | ~1000 if unset | Approximate output face count. | | targetTriangleCount | number | — | Raw engine density target; overrides targetQuads. | | edgeScaling | number | 1.0 | Edge scale (CLI-style). Larger → bigger / fewer quads. Useful range ~1.0–2.0. | | sharpEdgeThreshold | number | 90 | Dihedral angle (°) treated as a sharp feature. | | adaptivity | number | 0.51.0 in practice | Curvature adaptivity in [0, 1]. | | smoothNormals | boolean | true | Fill result.normals. | | smoothNormalDegrees | number | 0 | Resampling normal smooth; 0 disables. | | modelType | "organic" \| "hardSurface" | "organic" | Matches the desktop app switch. | | preserveSharpFeatures | boolean | false | Shortcut for hardSurface. | | preserveUVs | boolean | true if input has UVs | Closest-point UV transfer → result.uvs. | | allowHoles | boolean | false | Allow open shells. When false, the pipeline tries to seal; large residual holes throw. | | maxParts | number | 1 | How many connected shells to keep (largest first). | | minPartTriangles | number | 32 | Drop smaller islands before remesh. | | maxInputTriangles | number | auto | Soft cap; dense meshes are decimated with meshoptimizer before the native solve. | | onProgress | (progress, status) => void | — | progress in [0, 1]. | | moduleOptions | ModuleLoadOptions | — | WASM URL / binary / threads (first load per variant). |

Result shape

| Field | Description | | --- | --- | | vertices | Float32Array positions (xyz) | | quads | Uint32Array, 4 indices per face. A triangle is encoded as i2 === i3. | | indices | Triangulated index buffer for rendering | | normals | Optional smooth vertex normals | | uvs | Optional re-projected UVs | | quadCount | quads.length / 4 | | watertight | true if no boundary edges remain | | quality | "remeshed" (closed / ok) or "near-sealed" (native remesh with a small residual boundary) | | processingTimeMs | Wall time for the remesh |

Prefer checking quality / watertight before exporting production assets.

Web Worker (recommended in browsers)

remesh() runs heavy WASM on the calling thread. Offload it:

// remesh.worker.ts
import { remesh } from "@autoremesher/wasm";

self.onmessage = async (event) => {
  const { id, vertices, indices, options } = event.data;
  try {
    const result = await remesh(
      { vertices, indices },
      {
        ...options,
        moduleOptions: { threads: false }, // deterministic single-thread path
        onProgress: (progress, status) =>
          self.postMessage({ id, type: "progress", progress, status }),
      }
    );
    const transfer = [
      result.vertices.buffer,
      result.indices.buffer,
      result.quads.buffer,
    ];
    if (result.normals) transfer.push(result.normals.buffer);
    self.postMessage({ id, type: "done", result }, { transfer });
  } catch (error) {
    self.postMessage({
      id,
      type: "error",
      message: error instanceof Error ? error.message : String(error),
    });
  }
};

Bundlers and WASM loading

The binary ships next to its glue:

  • wasm/autoremesher.mjs + wasm/autoremesher.wasm (single-thread)
  • wasm/autoremesher-mt.mjs + wasm/autoremesher-mt.wasm (pthreads)

Vite / webpack 5 usually resolve new URL(..., import.meta.url) inside the package. If assets are relocated:

import wasmUrl from "@autoremesher/wasm/wasm/autoremesher.wasm?url"; // Vite

await remesh(input, {
  targetQuads: 2000,
  moduleOptions: { wasmUrl },
});

moduleOptions also accepts wasmBinary, Emscripten locateFile, and print / printErr.

Warm the module early:

import { loadAutoRemesherModule } from "@autoremesher/wasm";
await loadAutoRemesherModule();

Multithreading

await remesh(input, {
  moduleOptions: { threads: "auto" }, // or true / false
});
  • "auto" — pthreads when SharedArrayBuffer is available (browsers need COOP/COEP).
  • Use threadsSupported() to query the environment.
  • Gains are mainly on multi-island meshes; single solids see less benefit.
  • For a simple product path, prefer threads: false.

UV / attribute transfer

When the source has UVs, remesh() fills result.uvs by default. For arbitrary attributes:

import { transferAttribute } from "@autoremesher/wasm";

const colors = transferAttribute(
  { vertices: srcPositions, indices: srcTriangles },
  srcColors,
  3,
  result.vertices
);

Closest-point sampling can smear UV islands at seams.

Error handling

Failures reject with AutoRemesherError and a numeric code:

import { remesh, AutoRemesherError } from "@autoremesher/wasm";

try {
  await remesh(input, { targetQuads: 2000 });
} catch (error) {
  if (error instanceof AutoRemesherError) {
    console.error(error.code, error.message);
  }
}

Common cases: empty / invalid topology (-101, -2), collapsed or unusable solve (-6), residual holes when allowHoles is false (-7).

Tips

  • Prefer closed manifold meshes; weld UV seams before remesh when possible.
  • Start around targetQuads 500–3000 for previews; raise carefully for density.
  • Very coarse targets on thin shapes can collapse — raise density or adjust edgeScaling.
  • Peak memory tracks the intermediate resample; terminate workers between large jobs.
  • Multi-object exports: keep maxParts: 1 (default) unless you need several shells.

Development

Prerequisites

  • Node.js ≥ 18
  • For WASM rebuilds: CMake ≥ 3.16 and the Emscripten SDK
  • TypeScript-only changes need only Node

Scripts

npm install
npm run build:ts    # tsc → lib/ (ESM + CJS + types)
npm test            # node --test test/*.test.mjs
npm run build       # full: Emscripten WASM + TypeScript

Full native rebuild:

# Windows: use a bash-capable shell (Git Bash, WSL, etc.)
source /path/to/emsdk/emsdk_env.sh
npm run build:wasm
npm run build:ts
npm test

The Emscripten tree compiles AutoRemesher + a geogram 1.8.3 subset with Qt/TBB shims under emscripten/.

Tests

npm test

Coverage includes remesh on closed primitives, UV transfer, format parsers, quality / hole policy, and CJS load.

Publishing to npm

npm login
npm whoami          # must be a member of the @autoremesher org
npm pack --dry-run  # inspect tarball: lib/, wasm/, README, LICENSE
npm publish         # publishConfig.access = public

Only paths listed in package.json"files" are published (lib, wasm/*, README, LICENSE).

Contributing

Contributions are welcome.

  1. Fork and clone this repository.
  2. npm install && npm test.
  3. Prefer small, focused PRs (API, quality gates, docs, or WASM build).
  4. Keep npm test green; add a test when you fix a failure mode.
  5. Do not commit local assets (.stl dumps, test-out-*, debug logs).

Please file issues with a short mesh description (closed/open, tri count, options) and, when possible, a minimal OBJ/GLB.

Browser demo (included)

Full-viewport playground under examples/web: drag-and-drop mesh, pre-decimate large models, remesh in a Web Worker, inspect original vs quads, download OBJ.

# from the package root (lib/ is committed; rebuild with npm run build:ts if you change src/)
npm run demo:install
npm run demo
# → http://localhost:5173

Or:

cd examples/web
npm install
npm run dev

The demo depends on this package via "@autoremesher/wasm": "file:../..". It is not part of the npm tarball (files only ships lib, wasm, README, LICENSE) — clone the repo to run it.

Roadmap

  • [x] Single-thread WASM remesh + TypeScript API
  • [x] pthreads build behind COOP/COEP
  • [x] UV re-projection
  • [x] Topology / density quality gates + quality / watertight
  • [x] meshoptimizer pre-decimation for large inputs
  • [x] Browser demo playground (examples/web)
  • [ ] Better hard-surface / crease preservation
  • [ ] Feature curves / guide constraints (needs upstream engine support)
  • [ ] Smaller binary / streaming progress from native

License

MIT © Sarah Yung — see LICENSE.

This package redistributes WebAssembly builds of third-party software. See LICENSE for full notices. Upstream projects include:

| Project | License | Link | | --- | --- | --- | | AutoRemesher | MIT | huxingyi/autoremesher | | geogram | BSD-3-Clause | BrunoLevy/geogram | | Eigen | MPL-2.0 | eigen.tuxfamily.org | | isotropicremesher | MIT | (vendored with AutoRemesher) | | meshoptimizer | MIT | zeux/meshoptimizer |

Acknowledgments

  • Jeremy Hu — AutoRemesher
  • Geogram / OpenNL authors — parameterization and geometry kernels
  • Everyone who files issues and shares hard meshes

npm: @autoremesher/wasm
Issues: use this GitHub repository’s issue tracker after the project is published under the @autoremesher organization.