A TypeScript port of jsfeat β a computer-vision library β for the WebARKit project. jsfeatNext is actively maintained: its algorithms are continuously checked for numeric/behavioral parity against the original jsfeat via an automated test suite, and its internals have been refactored into one real module per algorithm (no more duplicated implementations). It's still pre-1.0 and evolving β see "Known limitations" below for the honest list of gaps.
npm install @webarkit/jsfeat-nextimport jsfeatNext from "@webarkit/jsfeat-next";
// algorithm modules are singletons β call them directly, no `new` (since 0.9.0)
const src = new jsfeatNext.matrix_t(width, height, jsfeatNext.U8_t | jsfeatNext.C1_t);
jsfeatNext.imgproc.grayscale(rgbaPixelData, width, height, src);In the browser (UMD build), the global is the namespace directly:
<script src="dist/jsfeatNext.js"></script>
<script>
jsfeatNext.imgproc.grayscale(rgbaPixelData, width, height, src);
</script>Upgrading from β€ 0.8.x? The
jsfeatNext.jsfeatNextdouble namespace and thenew jsfeatNext.imgproc()calling convention were removed in 0.9.0 β see the migration guide.
- TypeScript definitions, with full TSDoc on every public class/method (
npm run docsto generate a browsable API reference locally) - UMD (browser
<script>) + ESM builds, built with Vite library mode - npm package
- 250+ tests across 22 files: characterization tests asserting numeric/behavioral parity against the original jsfeat, plus property/invariant tests, ground-truth reference tests, and a registry of intentional divergences
These classes are attached to the jsfeatNext namespace (jsfeatNext.<name>):
cache Β· fast_corners Β· homography2d Β· affine2d Β· imgproc Β· keypoint_t Β· linalg Β· math Β· matmath Β· matrix_t Β· motion_estimator Β· ransac_params_t Β· optical_flow_lk Β· orb Β· pyramid_t Β· transform Β· yape Β· yape06
- Node.js v24 (see
.nvmrc; npm 11) - Build (UMD + ESM + type declarations):
npm installthennpm run build-ts- Produces
dist/jsfeatNext.js(UMD, browser globaljsfeatNext),dist/jsfeatNext.mjs(ESM), andtypes/ - Built with Vite library mode; webpack/babel are no longer used
- Produces
- Watch mode:
npm run dev-ts - Tests:
npm test(Vitest β characterization tests against the original jsfeat) - API docs:
npm run docs(TypeDoc, output todocs/api/, gitignored/local-only for now) - Benchmarks:
npm run bench(Vitest, A/B against the vendored original jsfeat) Β·npm run bench:ratiosfor the ratio summary alone
Every case runs both jsfeatNext and the vendored original jsfeat in the same process, and the number that matters is the ratio between them β absolute ops/s are not comparable across machines or even across runs on one machine.
The suite has already found and fixed several real slowdowns (#159, #165, #166), and it records the ones still open.
Read bench/README.md before interpreting any number β it documents the measured noise floor, how to take a clean measurement, and the current status of every finding.
CI runs a collection-only smoke check (npm run bench:smoke) that verifies the benchmarks still execute, without measuring anything. Actual measurement is manual: the Benchmarks workflow above is dispatch-only and never gates a build, because a shared runner is too noisy to draw conclusions from.
npm install @webarkit/jsfeat-next- Not every original jsfeat class is ported yet β
haarandbbf(Haar-cascade / BBF object detection) are not implemented. Tracked in #43 and #44. - The
transformmodule takesmatrix_targuments where original jsfeat's (never-shipped)transformmodule used raw arrays β same math, slightly different calling convention (see the parity audit, Axis 2).
The examples folder demonstrates both ways of consuming the library. Build first (npm run build-ts), then open the examples in a browser.
The camera demos use the modern ES-module entry point:
<script type="module">
import jsfeatNext from '../dist/jsfeatNext.mjs';
jsfeatNext.imgproc.grayscale(...);
</script>
β οΈ These must be served over HTTP β ES modules don't load fromfile://. Run a static server from the repo root, e.g.npx serve ., then browse tohttp://localhost:3000/examples/β¦.
They share the helpers in examples/js/demo-utils.mjs (webcam setup and canvas drawing) instead of repeating that boilerplate in every file.
| Example | Demonstrates |
|---|---|
grayscale.html |
color β grayscale conversion |
sample_boxblur.html |
box blur |
sample_gaussblur.html |
gaussian blur |
sample_equalize_hist.html |
histogram equalization |
sample_canny_edge.html |
Canny edge detector |
sample_sobel.html / sample_sobel_edge.html |
Sobel derivatives / edges |
sample_scharr.html |
Scharr derivatives |
sample_pyrdown.html |
image pyramid downsampling |
sample_fast_corners.html |
FAST corner detector |
sample_yape.html / sample_yape06.html |
YAPE / YAPE06 detectors |
sample_oflow_lk.html |
LucasβKanade optical flow (click to add points) |
sample_orb.html |
ORB descriptors + matching + homography |
sample_orb_pinball.html |
ORB pattern tracking on a reference image |
sample_warp_affine.html / sample_warp_perspective.html |
affine / perspective warps |
These small API demos load the UMD bundle and use the jsfeatNext global. They need no server and open directly from the filesystem:
<script src="../dist/jsfeatNext.js"></script>
<script>
const m = new jsfeatNext.matrix_t(320, 240, jsfeatNext.U8_t | jsfeatNext.C1_t);
</script>| Example | Demonstrates |
|---|---|
browser.html |
version, constants, matrix_t, keypoint_t, the shared cache |
matrix_t_example.html |
constructing a matrix_t |
mat_math_example.html |
matmath (3Γ3 identity) |
linalg_example.html |
linalg (SVD pseudo-inverse) |
orb_test.html |
orb.describe |
You can find some TypeScript examples in jsfeatNext-examples.
Every public class, interface, method and property has TSDoc comments. Run npm run docs to generate a full static HTML API reference locally (via TypeDoc) β hosting it publicly is tracked separately in webarkit/webarkit.github.io#49. You can also read the original jsfeat docs for background on the algorithms, though the calling convention differs (see "Known limitations" below).
See AGENTS.md for the canonical contribution conventions (Conventional Commits, PRs target dev not main, numeric-parity expectations) and MAINTAINERS.md for the release process.
Dependencies and GitHub Actions are kept current by Dependabot, which opens its own PRs against dev β they go through the same CI and review as any other change.
Releases are tagged X.Y.Z (never vX.Y.Z) and published automatically via GitHub Actions. Release notes (generated from Conventional Commits with git-cliff) live on the GitHub Releases page.