locus-ar
v1.1.25
Published
High-performance Augmented Reality (AR) engine for React and the Web. 100% Pure JavaScript image tracking, zero-dependencies, bio-inspired foveal attention, and Nanite-style feature extraction.
Maintainers
Readme
🛰️ Locus AR
🚀 Ultra-Fast AR Tracking • 100% Pure JavaScript • No TensorFlow.js Required
Locus AR is a next-generation Augmented Reality (AR) image tracking engine for React, Three.js, Node.js, and the Browser.
- ⚡ 100% Pure JavaScript: Zero TensorFlow.js dependencies, instant startup, sub-millisecond overhead.
- 🧬 Bio-Inspired Vision: Foveal attention and predictive coding reducing CPU consumption by up to 98%.
- 📐 Full Multi-Scale Pyramids: Robust tracking from close-up (scale 1.0) to far-distance (scale 0.05).
- 📦 JIT & Offline Compilers: Pass an image URL directly or load pre-compiled
.taarfiles.
📖 Table of Contents
- 🛠 Installation
- ⚡ Quick Start (3 Formas de Uso)
- 🖼️ Image Compiler API
- 📊 Performance Benchmarks
- 🔍 Visual Search & Embeddings
- 📄 License
🛠 Installation
# npm
npm install locus-ar
# bun
bun add locus-ar
# pnpm
pnpm add locus-ar⚡ Quick Start
1. React Component (<Locus /> + <LocusTransform />)
The simplest and most elegant declarative JSX syntax. Positions any UI card or 3D element directly over the physical marker with exact 3D homography:
import React from 'react';
import { Locus, LocusTransform } from 'locus-ar/client';
export const MyARApp = () => {
return (
<div style={{ width: '100vw', height: '100vh', position: 'relative' }}>
<Locus
targets={{ image: '/assets/card-target.png', label: 'business-card' }}
// Optional: test with static image without camera:
// source="/assets/test-scene.jpg"
>
{(detections) =>
detections.map((det) => (
<LocusTransform
key={det.targetIndex}
matrix={det.worldMatrix}
modelViewTransform={det.modelViewTransform}
screenCoords={det.screenCoords}
targetIndex={det.targetIndex}
>
<div style={{
width: '100%',
height: '100%',
boxSizing: 'border-box',
background: 'rgba(15, 23, 42, 0.9)',
border: '2px solid #a855f7',
borderRadius: '16px',
padding: '16px',
color: 'white',
backdropFilter: 'blur(12px)',
boxShadow: '0 12px 36px rgba(168, 85, 247, 0.35)',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between'
}}>
<h3>🔮 Marcador Fijado</h3>
<p>Inliers: {det.inliersCount}</p>
<button style={{ padding: '8px 12px', background: '#a855f7', color: '#fff', borderRadius: '8px', border: 'none' }}>
Interactuar
</button>
</div>
</LocusTransform>
))
}
</Locus>
</div>
);
};2. React Hook (useLocus)
For developers who need fine-grained control over tracking states, camera streams, and custom render loops:
import React, { useEffect, useRef, useMemo } from 'react';
import { useLocus } from 'locus-ar/client';
export const CustomAR = () => {
const videoRef = useRef<HTMLVideoElement>(null);
const targets = useMemo(() => [
{ image: '/assets/target.png', label: 'poster' }
], []);
const {
state, // 'idle' | 'initializing' | 'compiling' | 'tracking' | 'error'
detections, // Array of LocusDetection (worldMatrix, screenCoords, inliersCount...)
compilationProgress, // 0 - 100%
error, // Error string if any
start, // start(videoElement | canvasElement)
stop, // stop()
getProjectionMatrix // () => number[] (16 elements for Three.js)
} = useLocus(targets, {
width: 1280,
height: 720,
bioInspired: true
});
useEffect(() => {
if (videoRef.current) {
start(videoRef.current);
}
return () => stop();
}, [start, stop]);
return (
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
<video ref={videoRef} playsInline autoPlay muted style={{ width: '100%', height: '100%', objectFit: 'contain' }} />
{state === 'compiling' && <p>Compilando: {compilationProgress}%</p>}
{detections.map(det => (
<div key={det.targetIndex} style={{ position: 'absolute', top: 20, left: 20, color: '#34d399' }}>
🎯 Fijado: {det.label} ({det.inliersCount} inliers)
</div>
))}
</div>
);
};3. Three.js Native 3D Scene
Render real 3D meshes, lights, and materials directly aligned with the physical target:
import * as THREE from 'three';
import { Controller, OfflineCompiler } from 'locus-ar';
// 1. Setup Three.js Scene
const scene = new THREE.Scene();
const camera = new THREE.Camera();
camera.matrixAutoUpdate = false;
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(1280, 720, false);
document.body.appendChild(renderer.domElement);
// 2. Create AR Anchor Group
const anchorGroup = new THREE.Group();
anchorGroup.matrixAutoUpdate = false;
anchorGroup.visible = false;
scene.add(anchorGroup);
// 🟩 Add 3D Target Plane (1x1 unit mesh centered on marker)
const planeGeo = new THREE.PlaneGeometry(1, 1);
const planeMat = new THREE.MeshBasicMaterial({ color: 0x10b981, transparent: true, opacity: 0.5, side: THREE.DoubleSide });
const plane = new THREE.Mesh(planeGeo, planeMat);
anchorGroup.add(plane);
// 3. Initialize Locus AR Controller
const controller = new Controller({
inputWidth: 1280,
inputHeight: 720,
onUpdate: (data) => {
if (data.type === 'updateMatrix' && data.worldMatrix) {
anchorGroup.visible = true;
anchorGroup.matrix.fromArray(data.worldMatrix);
} else if (data.type === 'updateMatrix' && !data.worldMatrix) {
anchorGroup.visible = false;
}
}
});
// Set camera projection matrix
camera.projectionMatrix.fromArray(controller.getProjectionMatrix());
// 4. Load & Compile Target
const response = await fetch('./assets/target.png');
const blob = await response.blob();
const imgBitmap = await createImageBitmap(blob);
const canvas = document.createElement('canvas');
canvas.width = imgBitmap.width;
canvas.height = imgBitmap.height;
const ctx = canvas.getContext('2d')!;
ctx.drawImage(imgBitmap, 0, 0);
const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const compiler = new OfflineCompiler();
await compiler.compileImageTargets([{
width: imgData.width,
height: imgData.height,
data: new Uint8Array(imgData.data.buffer)
}], () => {});
const buffer = compiler.exportData();
const cleanBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
await controller.addImageTargetsFromBuffer(cleanBuffer);
// 5. Start Processing Video Stream
const video = document.createElement('video');
video.srcObject = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment', width: { ideal: 1280 }, height: { ideal: 720 } } });
await video.play();
controller.processVideo(video);
// Render loop
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();4. Vanilla JavaScript / HTML (createTracker)
Zero-configuration camera tracking for vanilla web pages:
<!DOCTYPE html>
<html>
<head>
<style>
#ar-container { width: 100vw; height: 100vh; position: relative; overflow: hidden; }
#overlay-card {
position: absolute;
display: none;
background: #10b981;
color: white;
padding: 20px;
border-radius: 8px;
}
</style>
</head>
<body>
<div id="ar-container">
<div id="overlay-card">
<h2>🚀 Locus AR Active</h2>
</div>
</div>
<script type="module">
import { createTracker } from 'locus-ar';
const card = document.getElementById('overlay-card');
const tracker = await createTracker({
targetSrc: './assets/card-target.png',
container: document.getElementById('ar-container'),
overlay: card,
callbacks: {
onFound: () => console.log('Target found!'),
onLost: () => console.log('Target lost'),
onUpdate: (data) => {
// data.worldMatrix -> 4x4 matrix
// data.screenCoords -> 2D points on screen
}
}
});
await tracker.startCamera();
</script>
</body>
</html>🖼️ Image Compiler API
Locus AR compiles target images into compact binary .taar files with multi-scale feature pyramids.
Compile programmatically:
import { OfflineCompiler } from 'locus-ar';
const compiler = new OfflineCompiler();
// Compile target (accepts ImageData, RGBA buffers, or grayscale)
await compiler.compileImageTargets([
{ width: 1024, height: 1024, data: rgbaUint8Array }
], (progress) => {
console.log(`Compilation progress: ${progress.toFixed(1)}%`);
});
// Export compressed .taar buffer (~70-100KB)
const taarBuffer = compiler.exportData();📊 Performance Benchmarks
| Metric | MindAR (TFJS) | Locus AR | Advantage | | :--- | :--- | :--- | :--- | | Compilation Time | ~23.50s | ~0.46s | 🚀 ~50x Faster | | Output Size (.taar) | ~770 KB | ~68 KB | 📉 91% Smaller | | TFJS Dependency | ~20 MB | 0 KB (Pure JS)| 📦 100% Elimination | | Memory Footprint | ~180 MB | ~18 MB | ⚡ 10x Lighter | | Frame Detection | ~45 ms | < 10 ms | 🎯 Real-Time 60 FPS |
🔍 Visual Search & Embeddings
Convert any image into a compact mathematical fingerprint (HDC vector) for instant similarity matching:
import { visualSearch } from 'locus-ar';
// Compute 16-byte embedding
const embedding1 = await visualSearch.compute('product-a.jpg');
const embedding2 = await visualSearch.compute('product-b.jpg');
// Instant cosine similarity
const similarity = await visualSearch.compare('product-a.jpg', 'product-b.jpg');
console.log(`Similarity: ${(similarity * 100).toFixed(1)}%`);📄 License
MIT © srsergiolazaro — Free for commercial and open-source use.
