I develop a virtual sunglass try-on app. Everything ok on desktop, but i unable to use front camera on mobile.
Here is my full code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<title>Face Tracking with AR.js</title>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/AR-js-org/[email protected]/aframe/build/aframe-ar.js"></script>
<style>
body { margin: 0; overflow: hidden; }
#controls { position: absolute; top: 10px; left: 10px; z-index: 10; }
</style>
</head>
<body>
<a-scene embedded arjs="sourceType: webcam; debugUIEnabled: false;" vr-mode-ui="enabled: false">
<a-marker-camera preset="hiro"></a-marker-camera>
<!-- Static model before face tracking starts -->
<a-entity id="sunglassesModel" gltf-model="https://apollocdn-cdn.s3.amazonaws.com/tryon/coolly/Coolley.gltf"
scale="0.005 0.005 0.005" position="0 1.5 -2" rotation="0 0 0" visible="true">
</a-entity>
<!-- Use a face tracking anchor -->
<a-entity id="faceAnchor" arjs-face-anchor>
<a-entity id="faceSunglassesModel" gltf-model="https://apollocdn-cdn.s3.amazonaws.com/tryon/coolly/Coolley.gltf"
scale="0.005 0.005 0.005" position="0 0 0" rotation="0 0 0" visible="false">
</a-entity>
</a-entity>
</a-scene>
<div id="controls">
<button onclick="changeModel('https://apollocdn-cdn.s3.amazonaws.com/tryon/coolly/Coolley.gltf')">Sunglasses 1</button>
<button onclick="changeModel('https://apollocdn-cdn.s3.amazonaws.com/tryon/generous/Generous.gltf')">Sunglasses 2</button>
<button onclick="changeModel('https://apollocdn-cdn.s3.amazonaws.com/tryon/posh/Posh.gltf')">Sunglasses 3</button>
</div>
<script>
async function initFrontCamera() {
const constraints = {
video: {
facingMode: { ideal: 'user' }, // Front camera
width: { ideal: 1280 },
height: { ideal: 720 }
}
};
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
const video = document.createElement('video');
video.srcObject = stream;
video.setAttribute('autoplay', '');
video.setAttribute('muted', '');
video.setAttribute('playsinline', '');
document.body.appendChild(video);
// Wait for the video stream to be ready
video.onloadedmetadata = () => {
const arSystem = document.querySelector('a-scene').systems['arjs'];
arSystem.sourceElement = video;
arSystem._initSource = function () {
this.context.arController.setVideo(video);
this.context.arController.setup(video);
};
arSystem.start();
};
} catch (error) {
console.error('Error accessing front camera:', error);
}
}
window.onload = () => {
initFrontCamera();
};
function changeModel(url) {
console.log('Changing model to: ' + url);
const sunglassesEntity = document.querySelector('#faceSunglassesModel');
sunglassesEntity.setAttribute('gltf-model', url);
}
// Handle face tracking state
AFRAME.registerComponent('arjs-face-anchor', {
init: function () {
this.el.sceneEl.addEventListener('markerFound', (event) => {
console.log('Face marker found');
const faceSunglassesModel = document.querySelector('#faceSunglassesModel');
faceSunglassesModel.setAttribute('visible', 'true');
const staticSunglassesModel = document.querySelector('#sunglassesModel');
staticSunglassesModel.setAttribute('visible', 'false');
});
this.el.sceneEl.addEventListener('markerLost', (event) => {
console.log('Face marker lost');
const faceSunglassesModel = document.querySelector('#faceSunglassesModel');
faceSunglassesModel.setAttribute('visible', 'false');
const staticSunglassesModel = document.querySelector('#sunglassesModel');
staticSunglassesModel.setAttribute('visible', 'true');
});
this.el.sceneEl.addEventListener('faceUpdate', (event) => {
const face = event.detail;
const sunglassesModel = document.getElementById('faceSunglassesModel');
if (face && sunglassesModel) {
const leftEye = face.getLandmark('leftEye');
const rightEye = face.getLandmark('rightEye');
const nose = face.getLandmark('noseTip');
if (leftEye && rightEye && nose) {
const eyeDistance = Math.sqrt(
Math.pow(rightEye.x - leftEye.x, 2) +
Math.pow(rightEye.y - leftEye.y, 2) +
Math.pow(rightEye.z - leftEye.z, 2)
);
console.log('Eye Distance:', eyeDistance);
const baseScale = 0.005;
const scaleFactor = eyeDistance / 300;
const scale = baseScale * scaleFactor;
sunglassesModel.object3D.scale.set(scale, scale, scale);
const eyeMidPoint = {
x: (leftEye.x + rightEye.x) / 2,
y: (leftEye.y + rightEye.y) / 2,
z: (leftEye.z + rightEye.z) / 2,
};
sunglassesModel.object3D.position.set(eyeMidPoint.x, eyeMidPoint.y - (eyeDistance / 2), eyeMidPoint.z);
const rotationY = Math.atan2(rightEye.y - leftEye.y, rightEye.x - leftEye.x);
sunglassesModel.object3D.rotation.set(0, rotationY, 0);
console.log('Adjusted Model scale:', sunglassesModel.object3D.scale);
console.log('Adjusted Model position:', sunglassesModel.object3D.position);
console.log('Adjusted Model rotation:', sunglassesModel.object3D.rotation);
}
}
});
}
});
</script>
</body>
</html>
i try facingMode: { ideal: ‘user’ } or facingMode: { ideal: ‘-webkit-user’ } nothing worked. when the page load the app uses front camera, but when is fully loaded it will switch back to the back camera.