Scannable assets. Grab another device to scan and experience the magic. Long press (or right click) any QR code to download.
Tap any QR code to isolate it for scanning.
Showcase
The core capabilities.
Rich Cards
JSON-driven layout mapping.
Custom HTML Elements
Mapping hidden DOM nodes in 3D.
Smart Text & Data
Regex parsed native integrations.
3D Models
WebGL .glb loaders.
Video Players
Liquid morphing media.
Image Frames
Static spatial assets.
Audio Players
Interactive widgets.
Custom Generator
Instantly create and download your own custom styled QR anchors. Right-click/long-press to download.
Live Configuration
Tracking & Performance
Engine & Advanced Setup
Changing these requires a full hardware/DOM reload.
Omni SpatialQR
Zero-Friction WebAR Framework. A blazing-fast Vanilla JS library for mapping rich HTML interfaces and 3D models perfectly onto physical QR codes.
The physical world is static. The digital world is limitless. Omni SpatialQR is the bridge between them.
Until now, Augmented Reality required massive friction: forcing users to download heavy apps, scanning weird proprietary markers, or waiting for bloated 3D engines to load. Omni SpatialQR changes the paradigm. It turns standard, everyday QR codes—on business cards, restaurant menus, retail packaging, and real estate signs—into instant, zero-friction spatial interfaces directly in the mobile browser.
Make your print media play video. Turn a coaster into a 3D showroom. Turn a poster into a glassmorphic checkout interface. It’s lightweight, instantly familiar to users, and feels like native magic.
README.md
A vanilla JavaScript library that calculates camera pose homography from the native BarcodeDetector API to project HTML DOM elements and Three.js WebGL models onto physical QR codes via mathematically precise CSS matrix3d transforms.
Installation
<script src="omni-spatial-qr.js"></script>
Minimal Quick Start
const visionAR = new OmniSpatialQR({
container: '#ar-wrapper',
type: 'dynamic'
});
visionAR.start();
// Essential for SPA (React/Vue) routing to prevent memory leaks
visionAR.stop();
Use Cases & Data Routing
Physical QR codes should be as simple as possible (low data density) so they scan instantly from far away. Omni SpatialQR provides two powerful architectures to keep your codes microscopic while rendering massive data payloads.
Use Case A: The Universal Billboard
Use this if your QR codes are standard URLs designed to be scanned by native iPhone/Android cameras to open your website. The library automatically extracts your query parameters (e.g. https://mysite.com?promo=vip).
If users scan codes inside your webapp, you don't need full URLs. Use custom URIs (e.g., omni:vip). This makes the physical QR code smaller, allowing the camera to track it significantly faster and from much further away.
const visionAR = new OmniSpatialQR({
type: 'dynamic',
uriPrefix: 'omni', // Intercepts "omni:vip"
assetResolver: async (payload) => {
// Payload is the raw string "vip"
const dbItem = await fetch(`/api/items/${payload}`);
return dbItem.json();
}
});
Use Case C: The 3D Model Viewer
Ideal for e-commerce or museums. Map physical items to their 3D digital twins automatically.
Omni URI Scheme: Prefix the string with type:payload. Example: video:https://mysite.com/vid.mp4 or 3d:duck.glb renders the specific player/model.
AssetResolver Overrides & Error Handling
If your backend returns a video URL without an extension (e.g. https://api.com/file_77), dynamic mode will fail. Your resolver can return a config object to force the engine.
Furthermore, if your database lookup fails, return null. The engine will gracefully abort the visual update and fire the onError hook.
CSS Resolution Nuance: The library uses a strict CSS reset (all: initial) to protect your layout, but explicitly inherits your font-family. Due to the default overlayResolution: 100, 1 unit equals 1 physical pixel relative to the QR code size. Scale your CSS padding and fonts accordingly!
Full Configuration API Reference
container (String): DOM selector for the AR viewport.
scale (Number): Base scale multiplier (Default 1.0).
position (String): 'center', 'top', 'bottom', 'left', 'right'.
gap (Number): Unit offset if position is not center.
overlayResolution (Number): Base render matrix (Default 100). Higher numbers increase clarity but can reduce performance. Use 100 for optimal performance, 200 for big scales and 400 only for computers.
spawnAnimation (Boolean): Triggers a premium Apple-style pop-up animation for all DOM overlays and 3D models when they spawn.
autoPlay (Boolean): Auto-plays injected media loops.
templates (Object): Maps IDs to hidden DOM elements for custom HTML rendering.
Lifecycle Events
onDetect(parsedData): Fires the instant a payload is decoded and extracted, before the UI builds. Perfect for firing a background analytics pixel or triggering an auto-download.
onTrackingRestored(): Fires when AR physically locks onto the square.
onTrackingLost(): Fires when AR loses physical tracking.
onClick(parsedData): Fires when the user taps anywhere on the AR overlay (excluding inner buttons/media controls which handle their own clicks natively). Great for interaction, animations or navigating to an external product page.
onError(err): Captures Camera, WebWorker, and Resolver failures gracefully.
Pro-Tips & Gotchas
HTTPS Requirement: Modern browsers strictly require https:// (or localhost) to access the getUserMedia camera API.
CORS for 3D: If you are loading .glb files from an external server (like AWS S3 or a custom CDN), ensure your server is configured with Access-Control-Allow-Origin: *, otherwise the WebGL canvas will block the download for security reasons.
Live Engine Methods
.setScale(number): Smoothly animates the scale dynamically. Snaps instantly if called while tracking is lost.
.set3DRotation(bool): Instantly starts or stops the 3D turntable animation.
.pause() / resume(): Gracefully releases camera hardware for modal/background views.
Physical QR Code Generator API
Don't use a third-party generator. Our static helper creates beautiful, branded physical anchors instantly. With maximum error correction (Level H) when adding an embedded logos.
const qr = await OmniSpatialQR.generate({
data: 'omni:promo1',
type: 'soft', // standard, soft, dots
size: 300,
color: '#18181b', // Dot color
bgColor: '#ffffff',// Background color
logo: '/logo.png' // Drops your brand into the center
});
document.body.appendChild(qr);