{"_id":"@autoremesher/wasm","name":"@autoremesher/wasm","dist-tags":{"latest":"0.2.0"},"versions":{"0.2.0":{"name":"@autoremesher/wasm","version":"0.2.0","description":"Automatic quad remeshing (AutoRemesher) compiled to WebAssembly, with a TypeScript-first API for Three.js, glTF, OBJ, and raw buffers.","keywords":["remesh","quad","retopology","mesh","wasm","webassembly","3d","threejs","gltf","geometry-processing"],"license":"MIT","author":{"name":"Sarah Yung","email":"sarahyung3d@gmail.com"},"homepage":"https://github.com/imsarah/autoremesher-wasm#readme","bugs":{"url":"https://github.com/imsarah/autoremesher-wasm/issues"},"repository":{"type":"git","url":"git+https://github.com/imsarah/autoremesher-wasm.git"},"publishConfig":{"access":"public"},"type":"module","main":"./lib/cjs/index.js","module":"./lib/esm/index.js","types":"./lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","import":"./lib/esm/index.js","require":"./lib/cjs/index.js"},"./three":{"types":"./lib/types/three.d.ts","import":"./lib/esm/three.js","require":"./lib/cjs/three.js"},"./wasm/autoremesher.mjs":"./wasm/autoremesher.mjs","./wasm/autoremesher.wasm":"./wasm/autoremesher.wasm","./wasm/autoremesher-mt.mjs":"./wasm/autoremesher-mt.mjs","./wasm/autoremesher-mt.wasm":"./wasm/autoremesher-mt.wasm","./package.json":"./package.json"},"sideEffects":false,"engines":{"node":">=18"},"scripts":{"build":"npm run build:wasm && npm run build:ts","build:wasm":"bash emscripten/build.sh","build:ts":"tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json && node scripts/postbuild.mjs","test":"node --test \"test/*.test.mjs\"","demo":"npm run dev --prefix examples/web","demo:install":"npm install --prefix examples/web","prepublishOnly":"npm run build:ts && npm test"},"peerDependencies":{"three":">=0.150.0"},"peerDependenciesMeta":{"three":{"optional":true}},"devDependencies":{"@types/node":"^22.0.0","@types/three":"^0.185.1","three":"^0.185.1","typescript":"^5.5.0"},"dependencies":{"meshoptimizer":"^1.2.0"},"_id":"@autoremesher/wasm@0.2.0","gitHead":"519ab81667b4c74de4b14774f3e96a224c918f3b","_nodeVersion":"22.18.0","_npmVersion":"11.5.2","dist":{"integrity":"sha512-qmWc4xrbQ/PrPuzl+VURSLchxrdHspabvZAurYi8g916GJUjxI9T+itUSfAk6oI4ZzlCo3iF2EWDN/waYHeb2w==","shasum":"1393133a41755a59a0108fce8010cd7d45cb884d","tarball":"https://registry.npmjs.org/@autoremesher/wasm/-/wasm-0.2.0.tgz","fileCount":36,"unpackedSize":2856149,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCiGIv/hjjHo7T0HF7SnHNFWPW4jJs1uS39+3mn9XgywwIhAPu1c0rK/8TdAUhEMUaFPOljbBnK4UVM2YLA04Uya4gr"}]},"_npmUser":{"name":"sarahyung","email":"yungsarah@gmail.com"},"directories":{},"maintainers":[{"name":"sarahyung","email":"yungsarah@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wasm_0.2.0_1784008922882_0.7735850287713568"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-14T06:02:02.709Z","0.2.0":"2026-07-14T06:02:03.055Z","modified":"2026-07-14T06:02:03.341Z"},"maintainers":[{"name":"sarahyung","email":"yungsarah@gmail.com"}],"description":"Automatic quad remeshing (AutoRemesher) compiled to WebAssembly, with a TypeScript-first API for Three.js, glTF, OBJ, and raw buffers.","homepage":"https://github.com/imsarah/autoremesher-wasm#readme","keywords":["remesh","quad","retopology","mesh","wasm","webassembly","3d","threejs","gltf","geometry-processing"],"repository":{"type":"git","url":"git+https://github.com/imsarah/autoremesher-wasm.git"},"author":{"name":"Sarah Yung","email":"sarahyung3d@gmail.com"},"bugs":{"url":"https://github.com/imsarah/autoremesher-wasm/issues"},"license":"MIT","readme":"# @autoremesher/wasm\n\n**Automatic quad remeshing in the browser and Node.js** — powered by WebAssembly.\n\nThis project ports [AutoRemesher](https://github.com/huxingyi/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.\n\n```bash\nnpm install @autoremesher/wasm\n```\n\n```ts\nimport { remesh } from \"@autoremesher/wasm\";\n\nconst result = await remesh(\n  { vertices, indices }, // Float32Array xyz + Uint32Array triangles\n  { targetQuads: 2000 }\n);\n\n// result.quads     — 4 indices per face (true quads + rare tris)\n// result.indices   — triangulated for GPU / Three.js\n// result.vertices  — remeshed positions\n// result.quality   — \"remeshed\" | \"near-sealed\"\n// result.watertight\n```\n\n> **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.\n\n---\n\n## Features\n\n- **Quad-dominant remesh** — native AutoRemesher / MIQ pipeline in WASM  \n- **TypeScript-first** — full `.d.ts` types, ESM + CommonJS  \n- **Flexible inputs** — raw buffers, OBJ text, GLB / glTF, or a Three.js `BufferGeometry`-like object  \n- **Self-contained** — ~1.1 MB single-thread WASM (+ optional pthreads build), no native install  \n- **Browser + Node** — same API; Node example included  \n- **UV re-projection** — closest-point transfer when the input has UVs  \n- **Quality gates** — topology checks, density scoring, safe hole fill, explicit `quality` / `watertight` on the result  \n- **Optional threads** — pthreads binary for multi-island speedups (needs COOP/COEP in browsers)\n\n## Repository layout\n\nThis repository is the full open-source package:\n\n```text\n.\n├── src/              TypeScript API (source of truth)\n├── lib/              Built ESM + CJS + types (published)\n├── wasm/             Prebuilt .mjs + .wasm (st + mt)\n├── emscripten/       Bindings, shims, build scripts\n├── cpp/              Vendored AutoRemesher + third-party C++\n├── test/             Node test suite\n├── examples/\n│   ├── node-remesh.mjs   CLI sample\n│   └── web/              Browser playground (Vite + React + Three)\n├── package.json      @autoremesher/wasm\n└── README.md\n```\n\nPrebuilt `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.\n\n## Installation\n\n```bash\nnpm install @autoremesher/wasm\n```\n\n| Package | Role |\n| --- | --- |\n| `@autoremesher/wasm` | Core remesher (this package) |\n| `meshoptimizer` | Runtime dependency (input decimation helpers) |\n| `three` | **Optional** peer — only if you use `@autoremesher/wasm/three` |\n\n## Quick start\n\n### Raw buffers\n\n```ts\nimport { remesh } from \"@autoremesher/wasm\";\n\nconst result = await remesh(\n  {\n    vertices: /* Float32Array length % 3 === 0 */,\n    indices: /* Uint32Array length % 3 === 0 */,\n  },\n  {\n    targetQuads: 2000,\n    adaptivity: 0.5,\n    onProgress: (p, status) => console.log(Math.round(p * 100), status),\n  }\n);\n\nconsole.log(result.quadCount, result.quality, result.watertight);\n```\n\n### Three.js\n\n```ts\nimport { remesh } from \"@autoremesher/wasm\";\nimport { fromBufferGeometry, toBufferGeometry } from \"@autoremesher/wasm/three\";\n\nconst result = await remesh(fromBufferGeometry(sourceGeometry), {\n  targetQuads: 4000,\n  adaptivity: 0.8,\n});\nmesh.geometry = toBufferGeometry(result);\n```\n\nYou can also pass a `BufferGeometry` (or any object with the same shape) straight to `remesh()`. The core package never imports `three`.\n\n### OBJ\n\n```ts\nimport { remesh, resultToObj } from \"@autoremesher/wasm\";\n\nconst objText = await fetch(\"model.obj\").then((r) => r.text());\nconst result = await remesh(objText, { targetQuads: 3000 });\nconst out = resultToObj(result); // native quad faces in OBJ\n```\n\n### GLB / glTF\n\n```ts\nimport { remesh } from \"@autoremesher/wasm\";\n\nconst glb = await fetch(\"model.glb\").then((r) => r.arrayBuffer());\nconst result = await remesh(glb, { targetQuads: 5000 });\n```\n\nTriangle primitives are merged before remeshing. External `.bin` URIs are not fetched — use GLB or embedded / data-URI buffers.\n\n### Node.js\n\n```js\nimport { remesh, resultToObj } from \"@autoremesher/wasm\";\nimport { readFile, writeFile } from \"node:fs/promises\";\n\nconst result = await remesh(await readFile(\"input.obj\", \"utf8\"), {\n  targetQuads: 2000,\n  onProgress: (p, status) => console.log(`${(p * 100) | 0}% ${status}`),\n});\nawait writeFile(\"output.obj\", resultToObj(result));\n```\n\nSee [`examples/node-remesh.mjs`](examples/node-remesh.mjs).\n\n## Options\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `targetQuads` | `number` | ~1000 if unset | Approximate output face count. |\n| `targetTriangleCount` | `number` | — | Raw engine density target; overrides `targetQuads`. |\n| `edgeScaling` | `number` | `1.0` | Edge scale (CLI-style). Larger → bigger / fewer quads. Useful range ~1.0–2.0. |\n| `sharpEdgeThreshold` | `number` | `90` | Dihedral angle (°) treated as a sharp feature. |\n| `adaptivity` | `number` | `0.5`–`1.0` in practice | Curvature adaptivity in `[0, 1]`. |\n| `smoothNormals` | `boolean` | `true` | Fill `result.normals`. |\n| `smoothNormalDegrees` | `number` | `0` | Resampling normal smooth; `0` disables. |\n| `modelType` | `\"organic\" \\| \"hardSurface\"` | `\"organic\"` | Matches the desktop app switch. |\n| `preserveSharpFeatures` | `boolean` | `false` | Shortcut for `hardSurface`. |\n| `preserveUVs` | `boolean` | `true` if input has UVs | Closest-point UV transfer → `result.uvs`. |\n| `allowHoles` | `boolean` | `false` | Allow open shells. When `false`, the pipeline tries to seal; large residual holes throw. |\n| `maxParts` | `number` | `1` | How many connected shells to keep (largest first). |\n| `minPartTriangles` | `number` | `32` | Drop smaller islands before remesh. |\n| `maxInputTriangles` | `number` | auto | Soft cap; dense meshes are decimated with meshoptimizer before the native solve. |\n| `onProgress` | `(progress, status) => void` | — | `progress` in `[0, 1]`. |\n| `moduleOptions` | `ModuleLoadOptions` | — | WASM URL / binary / threads (first load per variant). |\n\n### Result shape\n\n| Field | Description |\n| --- | --- |\n| `vertices` | `Float32Array` positions (xyz) |\n| `quads` | `Uint32Array`, 4 indices per face. A triangle is encoded as `i2 === i3`. |\n| `indices` | Triangulated index buffer for rendering |\n| `normals` | Optional smooth vertex normals |\n| `uvs` | Optional re-projected UVs |\n| `quadCount` | `quads.length / 4` |\n| `watertight` | `true` if no boundary edges remain |\n| `quality` | `\"remeshed\"` (closed / ok) or `\"near-sealed\"` (native remesh with a small residual boundary) |\n| `processingTimeMs` | Wall time for the remesh |\n\nPrefer checking `quality` / `watertight` before exporting production assets.\n\n## Web Worker (recommended in browsers)\n\n`remesh()` runs heavy WASM on the calling thread. Offload it:\n\n```ts\n// remesh.worker.ts\nimport { remesh } from \"@autoremesher/wasm\";\n\nself.onmessage = async (event) => {\n  const { id, vertices, indices, options } = event.data;\n  try {\n    const result = await remesh(\n      { vertices, indices },\n      {\n        ...options,\n        moduleOptions: { threads: false }, // deterministic single-thread path\n        onProgress: (progress, status) =>\n          self.postMessage({ id, type: \"progress\", progress, status }),\n      }\n    );\n    const transfer = [\n      result.vertices.buffer,\n      result.indices.buffer,\n      result.quads.buffer,\n    ];\n    if (result.normals) transfer.push(result.normals.buffer);\n    self.postMessage({ id, type: \"done\", result }, { transfer });\n  } catch (error) {\n    self.postMessage({\n      id,\n      type: \"error\",\n      message: error instanceof Error ? error.message : String(error),\n    });\n  }\n};\n```\n\n## Bundlers and WASM loading\n\nThe binary ships next to its glue:\n\n- `wasm/autoremesher.mjs` + `wasm/autoremesher.wasm` (single-thread)\n- `wasm/autoremesher-mt.mjs` + `wasm/autoremesher-mt.wasm` (pthreads)\n\nVite / webpack 5 usually resolve `new URL(..., import.meta.url)` inside the package. If assets are relocated:\n\n```ts\nimport wasmUrl from \"@autoremesher/wasm/wasm/autoremesher.wasm?url\"; // Vite\n\nawait remesh(input, {\n  targetQuads: 2000,\n  moduleOptions: { wasmUrl },\n});\n```\n\n`moduleOptions` also accepts `wasmBinary`, Emscripten `locateFile`, and `print` / `printErr`.\n\nWarm the module early:\n\n```ts\nimport { loadAutoRemesherModule } from \"@autoremesher/wasm\";\nawait loadAutoRemesherModule();\n```\n\n## Multithreading\n\n```ts\nawait remesh(input, {\n  moduleOptions: { threads: \"auto\" }, // or true / false\n});\n```\n\n- **`\"auto\"`** — pthreads when `SharedArrayBuffer` is available (browsers need [COOP/COEP](https://web.dev/articles/coop-coep)).\n- Use `threadsSupported()` to query the environment.\n- Gains are mainly on multi-island meshes; single solids see less benefit.\n- For a simple product path, prefer `threads: false`.\n\n## UV / attribute transfer\n\nWhen the source has UVs, `remesh()` fills `result.uvs` by default. For arbitrary attributes:\n\n```ts\nimport { transferAttribute } from \"@autoremesher/wasm\";\n\nconst colors = transferAttribute(\n  { vertices: srcPositions, indices: srcTriangles },\n  srcColors,\n  3,\n  result.vertices\n);\n```\n\nClosest-point sampling can smear UV islands at seams.\n\n## Error handling\n\nFailures reject with `AutoRemesherError` and a numeric `code`:\n\n```ts\nimport { remesh, AutoRemesherError } from \"@autoremesher/wasm\";\n\ntry {\n  await remesh(input, { targetQuads: 2000 });\n} catch (error) {\n  if (error instanceof AutoRemesherError) {\n    console.error(error.code, error.message);\n  }\n}\n```\n\nCommon cases: empty / invalid topology (`-101`, `-2`), collapsed or unusable solve (`-6`), residual holes when `allowHoles` is false (`-7`).\n\n## Tips\n\n- Prefer **closed** manifold meshes; weld UV seams before remesh when possible.  \n- Start around **`targetQuads` 500–3000** for previews; raise carefully for density.  \n- Very coarse targets on thin shapes can collapse — raise density or adjust `edgeScaling`.  \n- Peak memory tracks the intermediate resample; terminate workers between large jobs.  \n- Multi-object exports: keep `maxParts: 1` (default) unless you need several shells.\n\n## Development\n\n### Prerequisites\n\n- **Node.js** ≥ 18  \n- For WASM rebuilds: **CMake** ≥ 3.16 and the [Emscripten SDK](https://emscripten.org/)  \n- TypeScript-only changes need only Node\n\n### Scripts\n\n```bash\nnpm install\nnpm run build:ts    # tsc → lib/ (ESM + CJS + types)\nnpm test            # node --test test/*.test.mjs\nnpm run build       # full: Emscripten WASM + TypeScript\n```\n\nFull native rebuild:\n\n```bash\n# Windows: use a bash-capable shell (Git Bash, WSL, etc.)\nsource /path/to/emsdk/emsdk_env.sh\nnpm run build:wasm\nnpm run build:ts\nnpm test\n```\n\nThe Emscripten tree compiles AutoRemesher + a geogram 1.8.3 subset with Qt/TBB shims under `emscripten/`.\n\n### Tests\n\n```bash\nnpm test\n```\n\nCoverage includes remesh on closed primitives, UV transfer, format parsers, quality / hole policy, and CJS load.\n\n### Publishing to npm\n\n```bash\nnpm login\nnpm whoami          # must be a member of the @autoremesher org\nnpm pack --dry-run  # inspect tarball: lib/, wasm/, README, LICENSE\nnpm publish         # publishConfig.access = public\n```\n\nOnly paths listed in `package.json` → `\"files\"` are published (`lib`, `wasm/*`, README, LICENSE).\n\n## Contributing\n\nContributions are welcome.\n\n1. Fork and clone this repository.  \n2. `npm install` && `npm test`.  \n3. Prefer small, focused PRs (API, quality gates, docs, or WASM build).  \n4. Keep `npm test` green; add a test when you fix a failure mode.  \n5. Do not commit local assets (`.stl` dumps, `test-out-*`, debug logs).\n\nPlease file issues with a short mesh description (closed/open, tri count, options) and, when possible, a minimal OBJ/GLB.\n\n## Browser demo (included)\n\nFull-viewport playground under [`examples/web`](examples/web): drag-and-drop mesh, pre-decimate large models, remesh in a Web Worker, inspect original vs quads, download OBJ.\n\n```bash\n# from the package root (lib/ is committed; rebuild with npm run build:ts if you change src/)\nnpm run demo:install\nnpm run demo\n# → http://localhost:5173\n```\n\nOr:\n\n```bash\ncd examples/web\nnpm install\nnpm run dev\n```\n\nThe 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.\n\n## Roadmap\n\n- [x] Single-thread WASM remesh + TypeScript API  \n- [x] pthreads build behind COOP/COEP  \n- [x] UV re-projection  \n- [x] Topology / density quality gates + `quality` / `watertight`  \n- [x] meshoptimizer pre-decimation for large inputs  \n- [x] Browser demo playground (`examples/web`)  \n- [ ] Better hard-surface / crease preservation  \n- [ ] Feature curves / guide constraints (needs upstream engine support)  \n- [ ] Smaller binary / streaming progress from native  \n\n## License\n\nMIT © Sarah Yung — see [LICENSE](LICENSE).\n\nThis package redistributes WebAssembly builds of third-party software. See **LICENSE** for full notices. Upstream projects include:\n\n| Project | License | Link |\n| --- | --- | --- |\n| AutoRemesher | MIT | [huxingyi/autoremesher](https://github.com/huxingyi/autoremesher) |\n| geogram | BSD-3-Clause | [BrunoLevy/geogram](https://github.com/BrunoLevy/geogram) |\n| Eigen | MPL-2.0 | [eigen.tuxfamily.org](https://eigen.tuxfamily.org) |\n| isotropicremesher | MIT | (vendored with AutoRemesher) |\n| meshoptimizer | MIT | [zeux/meshoptimizer](https://github.com/zeux/meshoptimizer) |\n\n## Acknowledgments\n\n- [Jeremy Hu](https://github.com/huxingyi) — AutoRemesher  \n- Geogram / OpenNL authors — parameterization and geometry kernels  \n- Everyone who files issues and shares hard meshes  \n\n---\n\n**npm:** [`@autoremesher/wasm`](https://www.npmjs.com/package/@autoremesher/wasm)  \n**Issues:** use this GitHub repository’s issue tracker after the project is published under the `@autoremesher` organization.\n","readmeFilename":"README.md","_rev":"1-f46c0fa352ed05b3c7fa6a6c89aa94bb"}