Building Web AR with AR.js: A Pure Front‑End Solution
This article introduces a pure‑frontend approach to Web AR using AR.js, explains core technologies like WebRTC, JSARToolKit, A‑Frame, and Three.js, guides through HTTPS setup, demonstrates image‑tracking and video examples, and shows how to integrate Agora video calls for remote cat‑watching.
When browsing Apple’s website you notice a line at the bottom of each product page offering an AR preview, which works only on iOS because it relies on Apple’s ARKit. The article asks whether a universal, pure‑frontend Web AR solution exists.
Pure Front‑End Solution
The overall architecture can be summarised in a diagram (omitted). Using JSARToolKit as an example, the workflow is:
Obtain camera stream via WebRTC and draw the raw video onto a canvas.
JSARToolKit computes the pose matrix and renders virtual content.
Core Implementation Steps
Recognition : WebRTC captures the video stream.
Tracking : Libraries such as Tracking.js, JSFeat, ConvNetJS, deeplearn.js, keras.js.
Rendering : A‑Frame, Three.js, Pixi.js, Babylon.js.
Established Framework – AR.js
AR.js is a mature Web AR framework offering three main capabilities:
Image tracking – overlay 2D/3D assets on a detected picture.
Location‑based AR – attach content to real‑world GPS coordinates.
Marker tracking – display assets when a predefined marker is seen.
Getting Started with AR.js
Enable HTTPS for Camera Access
Because camera access requires a secure context, the article shows how to start a Vite + Vue 3 project with HTTPS using a single command. After initializing the scaffold, modify package.json to add --host to the dev script, then run:
npm run dev -- --httpsRun the Official Demo
Running the official AR.js demo confirms that the environment works; screenshots of the demo are included.
Example 1 – Display a Cat Image
Using image‑tracking, the following HTML creates a scene that shows a cat picture when the hiro marker is detected:
<body>
<a-scene embedded arjs>
<a-assets>
<img id="my-image" src="./src/assets/cat.jpg">
</a-assets>
<a-marker preset="hiro">
<a-image rotation="90 0 0" src="#my-image"></a-image>
</a-marker>
<a-entity camera></a-entity>
</a-scene>
</body>Explanation of the tags is provided: <a-scene> defines the AR scene, <a-marker> declares the reference image, and <a-assets> loads the cat picture.
Example 2 – Play a Video
A video can be displayed on a marker. The code loads a remote MP4 and registers a custom component to start/stop playback when the marker is found or lost:
<a-scene vr-mode-ui="enabled: false;" renderer='antialias: true; alpha: true; precision: mediump;' embedded arjs='trackingMethod: best; sourceType: webcam; debugUIEnabled: false;'>
<a-assets>
<video src="https://.../video.mp4" preload="auto" id="vid" response-type="arraybuffer" loop crossorigin webkit-playsinline muted playsinline></video>
</a-assets>
<a-nft videohandler type='nft' url='./src/assets/dataNFT/pinball' smooth="true" smoothCount="10" smoothTolerance="0.01" smoothThreshold="5">
<a-video src="#vid" position='50 150 -100' rotation='90 0 180' width='300' height='175'></a-video>
</a-nft>
<a-entity camera></a-entity>
</a-scene>
<script>
window.onload = function() {
AFRAME.registerComponent('videohandler', {
init: function() {
var marker = this.el;
this.vid = document.querySelector('#vid');
marker.addEventListener('markerFound', function() { this.vid.play(); }.bind(this));
marker.addEventListener('markerLost', function() { this.vid.pause(); this.vid.currentTime = 0; }.bind(this));
}
});
};
</script>Example 3 – Remote Cat Watching with Agora
The article then shows how to embed an Agora video call so a developer can watch their cat remotely. First, add the Agora SDK dependency, then use the following Vue 3 component (script‑setup syntax):
<script setup>
import AgoraRTC from "agora-rtc-sdk-ng";
import { ref } from "vue";
const joinBtn = ref(null);
const leaveBtn = ref(null);
let rtc = { localAudioTrack: null, client: null };
let options = {
appId: "2e76ff53e8c349528b5d05783d53f53c",
channel: "test",
token: "0062e76ff53e8c349528b5d05783d53f53cIADkw...",
uid: 123456,
};
rtc.client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
rtc.client.on("user-published", async (user, mediaType) => {
await rtc.client.subscribe(user, mediaType);
if (mediaType === "video") {
const remoteVideoTrack = user.videoTrack;
const remotePlayerContainer = document.createElement("div");
remotePlayerContainer.id = user.uid.toString();
remotePlayerContainer.style.width = "640px";
remotePlayerContainer.style.height = "480px";
document.body.append(remotePlayerContainer);
remoteVideoTrack.play(remotePlayerContainer);
}
if (mediaType === "audio") {
const remoteAudioTrack = user.audioTrack;
remoteAudioTrack.play();
}
rtc.client.on("user-unpublished", (user) => {
const remotePlayerContainer = document.getElementById(user.uid);
remotePlayerContainer && remotePlayerContainer.remove();
});
});
const handleJoin = async () => {
await rtc.client.join(options.appId, options.channel, options.token, options.uid);
rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
await rtc.client.publish([rtc.localAudioTrack, rtc.localVideoTrack]);
const localPlayerContainer = document.createElement("div");
localPlayerContainer.id = options.uid;
localPlayerContainer.style.width = "640px";
localPlayerContainer.style.height = "480px";
document.body.append(localPlayerContainer);
rtc.localVideoTrack.play(localPlayerContainer);
};
const handleLeave = async () => {
rtc.localAudioTrack.close();
rtc.localVideoTrack.close();
rtc.client.remoteUsers.forEach(user => {
const playerContainer = document.getElementById(user.uid);
playerContainer && playerContainer.remove();
});
await rtc.client.leave();
};
</script>
<template>
<div>
<button ref="joinBtn" @click="handleJoin" type="button" id="join">加入</button>
<button ref="leaveBtn" @click="handleLeave" type="button" id="leave">离开</button>
</div>
</template>
<style></style>Running this component opens a video call where the user can see the remote camera feed (e.g., a cat’s live view).
Conclusion
The author reflects that Web AR is fun and hopes more developers explore it. While Apple’s ARKit still offers smoother experiences, Web AR’s cross‑platform nature makes it promising for large‑scale adoption. The article also mentions the metaverse and encourages continued learning.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.