Skip to content

Repository files navigation

🛰️ Locus AR

Locus AR - High Performance Augmented Reality

npm version npm downloads License: MIT Bundle Size TypeScript Zero Dependencies

🚀 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 .taar files.

📖 Table of Contents


🛠 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.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages