Реалізація WebXR (VR/AR у браузері) на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація WebXR (VR/AR у браузері) на сайті
Складна
від 2 тижнів до 3 місяців
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація WebXR (VR/AR у браузері) на сайті

WebXR Device API дозволяє запускати VR та AR досвід прямо в браузері без встановлення програм. Користувач відкриває сторінку в Chrome на Android або Safari на iPhone і потрапляє в доповнену реальність. На десктопі з VR-гарнітурою (Meta Quest Browser, Valve Index + SteamVR) — у віртуальну.

Підтримка браузерами

AR (immersive-ar): Chrome Android 90+, Samsung Internet 14+. iOS/Safari — через WebXR Viewer або нативний AR Quick Look (USDZ-файли).

VR (immersive-vr): Chrome Android з гарнітурою Cardboard, Meta Quest Browser, Firefox Reality, Valve Index через SteamVR.

Inline (3D у сторінці без гарнітури): усі браузери з WebGL.

Перевірка підтримки:

const isARSupported = await navigator.xr?.isSessionSupported('immersive-ar')
const isVRSupported = await navigator.xr?.isSessionSupported('immersive-vr')

Three.js + WebXR

Three.js має вбудовану підтримку WebXR:

npm install three @types/three
import * as THREE from 'three'
import { ARButton } from 'three/examples/jsm/webxr/ARButton'
import { VRButton } from 'three/examples/jsm/webxr/VRButton'
import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory'

function WebXRScene({ mode }: { mode: 'ar' | 'vr' }) {
  const mountRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const container = mountRef.current!

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.setSize(container.clientWidth, container.clientHeight)
    renderer.xr.enabled = true  // Включаємо WebXR
    container.appendChild(renderer.domElement)

    const scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera(70, container.clientWidth / container.clientHeight, 0.01, 100)

    // Освітлення
    scene.add(new THREE.AmbientLight(0xffffff, 1))
    const dirLight = new THREE.DirectionalLight(0xffffff, 2)
    dirLight.position.set(0, 5, 3)
    scene.add(dirLight)

    // Кнопка AR/VR
    const button = mode === 'ar'
      ? ARButton.createButton(renderer, {
          requiredFeatures: ['hit-test'],        // Обнаруження поверхні
          optionalFeatures: ['dom-overlay'],     // UI поверх AR
          domOverlay: { root: container },
        })
      : VRButton.createButton(renderer)

    document.body.appendChild(button)

    // Контролери VR
    if (mode === 'vr') {
      const controllerModelFactory = new XRControllerModelFactory()

      for (let i = 0; i < 2; i++) {
        const controller = renderer.xr.getController(i)
        controller.addEventListener('selectstart', onSelectStart)
        controller.addEventListener('selectend', onSelectEnd)
        scene.add(controller)

        const controllerGrip = renderer.xr.getControllerGrip(i)
        controllerGrip.add(controllerModelFactory.createControllerModel(controllerGrip))
        scene.add(controllerGrip)
      }
    }

    // Hit testing для AR (розміщення об'єктів на поверхнях)
    let hitTestSource: XRHitTestSource | null = null
    let hitTestSourceRequested = false
    const reticle = createReticle()
    scene.add(reticle)

    renderer.xr.addEventListener('sessionstart', async () => {
      if (mode !== 'ar') return
      const session = renderer.xr.getSession()!
      const viewerSpace = await session.requestReferenceSpace('viewer')
      hitTestSource = await session.requestHitTestSource!({ space: viewerSpace })!
    })

    renderer.setAnimationLoop((timestamp, frame) => {
      if (mode === 'ar' && frame) {
        // Hit test — знаходимо поверхню під камерою
        const referenceSpace = renderer.xr.getReferenceSpace()!
        const hitTestResults = frame.getHitTestResults(hitTestSource!)

        if (hitTestResults.length > 0) {
          const hit = hitTestResults[0]
          const pose = hit.getPose(referenceSpace)
          if (pose) {
            reticle.visible = true
            reticle.matrix.fromArray(pose.transform.matrix)
          }
        } else {
          reticle.visible = false
        }
      }

      renderer.render(scene, camera)
    })

    function onSelectStart(event: THREE.Event) {
      // При натисканні на контролер в AR — розміщуємо об'єкт на поверхні
      if (reticle.visible) {
        const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1)
        const material = new THREE.MeshStandardMaterial({ color: 0x2563eb })
        const mesh = new THREE.Mesh(geometry, material)
        mesh.position.setFromMatrixPosition(reticle.matrix)
        mesh.quaternion.setFromRotationMatrix(reticle.matrix)
        scene.add(mesh)
      }
    }

    return () => {
      renderer.setAnimationLoop(null)
      renderer.dispose()
      button.remove()
      container.removeChild(renderer.domElement)
    }
  }, [mode])

  return (
    <div ref={mountRef} style={{ width: '100%', height: '600px', position: 'relative' }} />
  )
}

function createReticle(): THREE.Mesh {
  const geometry = new THREE.RingGeometry(0.05, 0.07, 32).rotateX(-Math.PI / 2)
  const material = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide })
  const reticle = new THREE.Mesh(geometry, material)
  reticle.matrixAutoUpdate = false
  reticle.visible = false
  return reticle
}

A-Frame: декларативний WebXR

Для більш простих VR-сцен без глибокої кастомізації:

npm install aframe
<!-- Повнофункціональна VR-сцена в HTML -->
<a-scene>
  <a-sky color="#1a1a2e"></a-sky>

  <!-- Навколишнього середовище -->
  <a-plane position="0 0 0" rotation="-90 0 0" width="20" height="20" color="#0a0a1a"></a-plane>

  <!-- Інтерактивний об'єкт -->
  <a-box
    position="-1 1 -3"
    rotation="0 45 0"
    color="#2563eb"
    animation="property: rotation; to: 0 405 0; loop: true; dur: 4000; easing: linear"
    event-set__mouseenter="color: #60a5fa"
    event-set__mouseleave="color: #2563eb"
    cursor-listener
  ></a-box>

  <!-- Камера з курсором для гарнітур без контролерів -->
  <a-camera>
    <a-cursor
      animation__click="property: scale; startEvents: click; from: 0.1 0.1 0.1; to: 1 1 1; dur: 150"
    ></a-cursor>
  </a-camera>
</a-scene>

iOS: AR Quick Look

Safari iOS не підтримує WebXR AR, але підтримує AR Quick Look через USDZ-файли:

<!-- Нативний AR на iOS через USDZ -->
<a
  href="/models/product.usdz"
  rel="ar"
  id="ar-link"
>
  <img src="/models/product-preview.jpg" alt="Переглянути в AR" />
  <span>Дивитися у вашому інтер'єрі</span>
</a>
// Визначаємо платформу та показуємо потрібну кнопку
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent)
const isAndroid = /Android/.test(navigator.userAgent)

if (isIOS) {
  // Показуємо посилання на USDZ
  document.getElementById('ar-link')!.style.display = 'block'
} else if (isAndroid && await navigator.xr?.isSessionSupported('immersive-ar')) {
  // WebXR AR для Android Chrome
  document.getElementById('ar-button')!.style.display = 'block'
}

Конвертація 3D-моделей

Для AR Quick Look потрібен USDZ (iOS), для WebXR — GLTF. Конвертація через Blender або CLI:

# GLTF → USDZ через Apple Reality Converter (macOS) або онлайн-сервіси
# GLB → USDZ через usd-from-gltf (npm)
npm install -g usd-from-gltf
gltf-to-usd model.glb model.usdz

Що ми робимо

Оцінюємо цільові пристрої (Android WebXR, iOS USDZ, VR-гарнітури). Реалізуємо AR-переглядання товару з hit-testing — користувач бачить товар у своєму інтер'єрі. Паралельно готуємо USDZ-файли для iOS. Тестуємо на реальних пристроях.

Строк: AR-переглядання товару (Android + iOS) — 5–7 днів. Інтерактивна VR-сцена з контролерами — 8–12 днів.