npm.io
8.0.1 • Published 13h ago

capacitor-ar-scanner

Licence
MIT
Version
8.0.1
Deps
0
Size
178 kB
Vulns
0
Weekly
0

capacitor-ar-scanner

AR/LiDAR camera preview, 3D scanning and real-world volume/dimension measurement for Capacitor, powered by ARKit (iOS) and ARCore (Android). Built for AI/ML capture pipelines: it renders a native camera preview behind a transparent WebView and returns precise measurements plus base64 frames you can feed straight into a model.

Features

  • Native AR camera preview behind a transparent WebView (your UI composites on top).
  • Real-world width / height / depth / volume from LiDAR depth (oriented bounding box).
  • Live wireframe mesh overlay and scan-state events while you aim.
  • Dual image capture: high-res (for AI/ML analysis) + thumbnail (for display/storage).
  • Torch control.
  • Self-healing preview: recovers from the long-idle cold-start white/blank screen and reports camera-health diagnostics.

Compatibility

Plugin Capacitor
8.x 8.x

The plugin's major version tracks Capacitor's major version.

Installation

npm install capacitor-ar-scanner
npx cap sync

iOS

  • Minimum deployment target: iOS 15.0.
  • Best results require a LiDAR-capable device; non-LiDAR devices fall back to image-only capture.
  • Add a camera usage description to ios/App/App/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Used to scan and measure objects with the camera.</string>

The plugin uses ARKit and SceneKit. The preview is an ARSCNView inserted below the (transparent) WebView, so make sure your web UI uses a transparent background while the preview is active.

Android

  • Requires an ARCore-supported device.
  • Add the camera permission to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />

Note: the Android implementation currently provides image-only capture; full measurement parity with iOS LiDAR is in progress.

Usage

import { ARScanner } from 'capacitor-ar-scanner';

// 1. Check support
const support = await ARScanner.checkSupport();
if (!support.isSupported) return;

// 2. Listen for live scan events (tracking, mesh, warnings, health)
const handle = await ARScanner.addListener('scanEvent', (event) => {
  if (event.type === 'health' && event.status) {
    // e.g. report 'stalled' | 'recovered' | 'opaqueReasserted' to analytics
    console.log('camera health:', event.status, event.attempt, event.staleSeconds);
  }
  if (event.type === 'meshReady') {
    console.log('ready to capture');
  }
});

// 3. Start the preview (transparent WebView required)
await ARScanner.startPreview({ mode: 'lidar' });

// 4. Capture + measure
const result = await ARScanner.capture();
console.log(`${result.width} × ${result.height} × ${result.depth} cm, ${result.volume} cm³`);
// result.capturedImageBase64 -> send to your AI/ML model

// 5. Stop + clean up
await ARScanner.stopPreview();
await handle.remove();

API

checkSupport()
checkSupport() => Promise<SupportResult>

Check whether AR scanning is available on the current device and what depth quality to expect (LiDAR vs world-tracking only).

Returns: Promise<SupportResult>

Since: 8.0.0


startPreview(...)
startPreview(options?: PreviewOptions | undefined) => Promise<{ started: boolean; }>

Start the native AR camera preview rendered behind a transparent WebView.

On iOS the preview is an ARSCNView inserted below the WebView; the WebView is kept transparent so your UI composites on top of the live camera.

On Android the returned promise resolves only once the CameraX use cases are actually bound (since 8.0.1), so a resolved promise means capture() is safe to call. It rejects if the camera fails to bind or permission is denied.

Param Type
options PreviewOptions

Returns: Promise<{ started: boolean; }>

Since: 8.0.0


stopPreview()
stopPreview() => Promise<{ stopped: boolean; }>

Stop the AR camera preview and tear down the AR session, restoring the WebView to its opaque state. Safe to call when no preview is running.

Returns: Promise<{ stopped: boolean; }>

Since: 8.0.0


capture()
capture() => Promise<ScanResult>

Capture the current frame and measure the object at the center of the viewfinder, returning real-world dimensions plus base64 images for any downstream AI/ML analysis.

Returns: Promise<ScanResult>

Since: 8.0.0


setTorch(...)
setTorch(options: TorchOptions) => Promise<{ enabled: boolean; }>

Toggle the device torch (flashlight) while the preview is running.

Param Type
options TorchOptions

Returns: Promise<{ enabled: boolean; }>

Since: 8.0.0


addListener('scanEvent', ...)
addListener(eventName: 'scanEvent', listener: (event: ScanEvent) => void) => Promise<PluginListenerHandle>

Listen for live scan events emitted during the preview: tracking state, mesh progress, capture warnings/errors and camera-health diagnostics.

Param Type
eventName 'scanEvent'
listener (event: ScanEvent) => void

Returns: Promise<PluginListenerHandle>

Since: 8.0.0


removeAllListeners()
removeAllListeners() => Promise<void>

Remove all listeners registered by this plugin.

Since: 8.0.0


Interfaces
SupportResult
Prop Type Description Since
isSupported boolean Whether AR (world tracking) is supported at all on this device. 8.0.0
hasLidar boolean Whether the device has a LiDAR sensor (high-accuracy depth). 8.0.0
hasDepthApi boolean Whether a depth API is available without LiDAR (reserved for future use). 8.0.0
depthQuality 'high' | 'medium' | 'low' | 'none' Expected depth/measurement quality on this device. 8.0.0
PreviewOptions
Prop Type Description Default Since
mode 'lidar' Preview mode. Currently only 'lidar' (depth-aware world tracking) is supported; the plugin gracefully falls back to image-only on devices without a LiDAR sensor. 8.0.0
forceLidarOff boolean Force LiDAR/scene-reconstruction off even on capable devices (image-only capture). Useful for debugging or to match Android behavior. false 8.0.0
ScanResult
Prop Type Description Since
hasLidar boolean Whether the measurement used LiDAR depth (true) or was image-only (false). 8.0.0
width number Object width in centimeters. 8.0.0
height number Object height in centimeters. 8.0.0
depth number Object depth in centimeters. 8.0.0
volume number Object volume in cubic centimeters (oriented bounding box, W × H × D). 8.0.0
depthQuality 'high' | 'medium' | 'low' | 'estimated' Quality of the depth data used for this measurement. 8.0.0
pointCount number Number of depth points used in the measurement. 8.0.0
scanMode 'single' | 'multi-angle' Whether this was a single capture or a multi-angle scan. 8.0.0
cameraAngle number Angle of the camera relative to the measured surface, in degrees. 8.0.0
measureMethod 'lidar' The measurement method used. 8.0.0
capturedImageBase64 string High-resolution (1280px) JPEG, base64-encoded, intended for AI/ML analysis. Not persisted by the plugin. 8.0.0
thumbnailBase64 string Thumbnail (1024px) JPEG, base64-encoded, intended for display/storage. 8.0.0
TorchOptions
Prop Type Description Since
enabled boolean Whether the torch should be on (true) or off (false). 8.0.0
PluginListenerHandle
Prop Type
remove () => Promise<void>
ScanEvent
Prop Type Description Since
type 'error' | 'tracking' | 'meshProgress' | 'meshReady' | 'warning' | 'processing' | 'health' The kind of event being emitted. 8.0.0
trackingState 'normal' | 'limited' | 'notAvailable' For type: 'tracking': the current AR tracking state. 8.0.0
limitedReason 'initializing' | 'excessiveMotion' | 'insufficientFeatures' | 'relocalizing' For type: 'tracking' with a limited state: why tracking is limited. 8.0.0
meshCount number For type: 'meshProgress' | 'meshReady': number of mesh anchors so far. 8.0.0
vertexCount number For type: 'meshProgress' | 'meshReady': total reconstructed vertices. 8.0.0
isStable boolean For type: 'meshProgress': whether the mesh has stabilized. 8.0.0
isReady boolean For type: 'meshProgress': whether enough mesh exists to capture. 8.0.0
message string For type: 'warning' | 'error': a human-readable message. 8.0.0
code CaptureIssueCode For type: 'warning' | 'error': a machine-readable issue code. 8.0.0
angle number For type: 'warning' (HOLD_LEVEL): the offending surface angle in degrees. 8.0.0
status string For type: 'processing': the capture phase. For type: 'health': one of 'stalled' | 'recovered' | 'sessionFailed' | 'interrupted' | 'interruptionEnded' | 'noSuperview' | 'opaqueReasserted'. 8.0.0
staleSeconds number Health diagnostics: seconds since the last camera frame when a stall was detected. 8.0.0
attempt number Health diagnostics: which self-heal attempt this is. 8.0.0
Type Aliases
CaptureIssueCode

Codes describing why a capture could not produce a measurement.

'NO_SURFACE' | 'NOT_ENOUGH_DEPTH' | 'CANNOT_ISOLATE' | 'HOLD_LEVEL'

Changelog

See CHANGELOG.md.

License

MIT

Keywords