lunar-webar-js
v1.0.5
Published
**Browser-native image tracking WebAR SDK** — detect and track images in real-time using your camera, then overlay 3D content with Three.js.
Readme
Lunar WebAR SDK
Browser-native image tracking WebAR SDK — detect and track images in real-time using your camera, then overlay 3D content with Three.js.
No cloud. No app install. Just the browser.
Features
- 🎯 Image Tracking — Detect and track predefined images in real-time
- 📷 Camera Management — Auto-select rear camera on mobile, webcam on desktop
- 🧮 6DOF Pose Estimation — Position, rotation, quaternion, and 4×4 matrix output
- 🎮 Three.js Integration — Attach 3D models to tracked images
- 🔄 Multiple Targets — Track up to 10 images simultaneously
- 📦 Asset Manager — Load GLB/GLTF models, textures, and audio
- 🧵 Web Worker — CV processing off the main thread
- 🐛 Debug Mode — Visualize feature points, matching lines, and FPS
- 💡 TypeScript-first — Full type definitions for a great DX
- 🌐 Cross-browser — Chrome, Edge, Firefox, Safari
Quick Start
Installation
npm install lunar-webar-js threeBasic Usage
<div id="ar-container" style="width: 100vw; height: 100vh; position: relative;">
<canvas id="ar-canvas" style="width: 100%; height: 100%;"></canvas>
</div>import { Lunar } from 'lunar-webar-js';
// 1. Create the AR instance
const ar = new Lunar({
canvas: document.getElementById('ar-canvas') as HTMLCanvasElement,
debug: true, // Enable debug mode
});
// 2. Register an image target
await ar.addTarget({
id: 'lion',
image: 'targets/lion.jpg',
physicalWidth: 0.1, // 10cm
});
// 3. Load and attach a 3D model
const model = await ar.assets.loadModel('models/lion.glb');
ar.attach('lion', model);
// 4. Listen for events
ar.on('targetFound', (e) => {
console.log(`Found: ${e.targetId}`);
});
ar.on('targetLost', (e) => {
console.log(`Lost: ${e.targetId}`);
});
// 5. Start!
await ar.start();API Reference
new Lunar(config)
Create a new SDK instance.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| canvas | HTMLCanvasElement | required | Canvas element for rendering |
| debug | boolean | false | Enable debug overlay |
| maxTargets | number | 10 | Max simultaneous targets |
| cameraFacing | 'environment' \| 'user' | 'environment' | Camera selection |
| cameraWidth | number | 640 | Desired resolution width |
| cameraHeight | number | 480 | Desired resolution height |
| smoothingFactor | number | 0.5 | Pose smoothing (0–1) |
| minMatchCount | number | 15 | Min feature matches for detection |
| maxFeatures | number | 500 | Max features extracted per frame (lower optimizes speed) |
| detectionInterval| number | 5 | Frames between full detections (higher optimizes speed) |
| lockPoseOnFound| boolean | false | Lock the 3D object's position stably on first detection |
| logLevel | LogLevel | 'warn' | Console log level |
Lifecycle
await ar.start(); // Start camera + tracking
await ar.stop(); // Stop (can restart)
ar.destroy(); // Full cleanup (cannot reuse)Target Management
await ar.addTarget({ id: 'lion', image: 'lion.jpg' });
await ar.addTargets([
{ id: 'lion', image: 'lion.jpg' },
{ id: 'elephant', image: 'elephant.jpg' },
]);Attachments & Gestures
// Attach a 3D object to follow the target
ar.attach('lion', threeJsObject);
ar.detach('lion');
// Enable touch gestures for an attached object
// Second argument specifies maximum rotation (in degrees, default: 45)
ar.gesture.enableRotate('lion', 360);
// Second argument specifies maximum zoom multiplier (default: 2)
ar.gesture.enablePinch('lion', 1.5);
// Disable all gestures
ar.gesture.disableAll('lion'); Events
ar.on('cameraReady', (e) => { /* { width, height } */ });
ar.on('cameraError', (e) => { /* { error, message } */ });
ar.on('targetFound', (e) => { /* { targetId, pose, confidence } */ });
ar.on('targetLost', (e) => { /* { targetId } */ });
ar.on('trackingUpdate', (e) => { /* { results, fps, timestamp } */ });
ar.on('sdkReady', (e) => { /* { version, timestamp } */ });
ar.on('sdkDestroyed', (e) => { /* { timestamp } */ });Asset Manager
const model = await ar.assets.loadModel('model.glb');
const texture = await ar.assets.loadTexture('image.png');
const audio = await ar.assets.loadAudio('sound.mp3');Debug Utilities
If you initialize the SDK with debug: true, you can toggle the visibility of the visual feature-point overlay and the FPS/performance stats panel dynamically:
ar.setDebugStatsVisible(true); // Show FPS and tracking status panel
ar.setDebugOverlayVisible(false); // Hide the canvas feature-point overlayArchitecture
Application
│
▼
Lunar (Public API)
│
├── CameraManager ─── getUserMedia
│
├── ImageTracker
│ ├── FeatureDetector (ORB)
│ ├── FeatureMatcher (BFMatcher)
│ ├── HomographyEstimator (RANSAC)
│ └── OpticalFlowTracker (Lucas-Kanade)
│
├── PoseEstimator (solvePnP)
│ └── PoseFilter (EMA smoothing)
│
├── ThreeJSRenderer
│ ├── CameraBackground
│ └── AnchorGroup (per target)
│
├── AssetManager (GLB/GLTF/PNG/MP3)
│
└── EventEmitter (typed events)Technology Stack
| Layer | Technology | |-------|-----------| | Language | TypeScript | | Build | Vite (library mode) | | Rendering | Three.js | | Computer Vision | OpenCV.js (WASM) | | Math | gl-matrix | | Testing | Vitest |
Browser Support
| Browser | Support | |---------|---------| | Chrome 90+ | ✅ | | Edge 90+ | ✅ | | Firefox 90+ | ✅ | | Safari 15+ | ✅ |
License
MIT
