# Examples

Complete, self-contained pages for a few common scenarios, combining the [Configuration Reference](configuration-reference.md) and the [`DiscoVR` class](discovr-class-api.md). Copy one as a starting point and adapt it.

## Virtual tour

An environment with a few 3D models placed around it, and free movement/teleport — no multiplayer, no demo content.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Virtual Tour</title>
</head>
<body>
    <discovr
        environment="preset:forest;groundColor:#2d4a1f"
        playerRig="enable:true"
    ></discovr>

    <script type="module" src="https://core.discovr-engine.eu/discovr-core.js"></script>
    <script type="module">
        function whenSceneReady(callback) {
            var scene = document.querySelector('a-scene');
            if (scene) {
                if (scene.hasLoaded) callback();
                else scene.addEventListener('loaded', callback);
            } else {
                setTimeout(() => whenSceneReady(callback), 100);
            }
        }

        whenSceneReady(() => {
            var discovr = new window.DiscoVR();
            discovr.addAsset("statue", "models/statue.glb");
            discovr.addModel("statue", { position: "0 0 -5" }, "statue1");
            discovr.addModel("statue", { position: "5 0 -8", rotation: "0 45 0" }, "statue2");
        });
    </script>
</body>
</html>
```

## Multiplayer meetup room

A shared room with voice chat, text chat, and named avatars. Everyone who opens this page with the same `roomName` lands together.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Meetup Room</title>
</head>
<body>
    <discovr
        presets="defaultScene:true;defaultLights:true"
        environment="preset:default"
        playerRig="enable:true"
        network="enable:true;roomName:team-meetup;showChat:true;showCam:true;showMic:true;showAvatarName:true;positionalAudio:true"
        interface="userClick:true;title:Team Meetup"
    ></discovr>

    <script type="module" src="https://core.discovr-engine.eu/discovr-core.js"></script>
</body>
</html>
```

`interface:userClick:true` is required here so visitors get a "click to enter" prompt — browsers block microphone/audio access without that initial user gesture.

## Physics playground

Enables the built-in physics demo content (a ball rolling down ramps) to sanity-check that PhysX is working, as a starting point for your own physics-driven scene.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Physics Playground</title>
</head>
<body>
    <discovr
        presets="defaultScene:true;defaultLights:true;defaultContents:true"
        physics="true"
        playerRig="enable:true"
    ></discovr>

    <script type="module" src="https://core.discovr-engine.eu/discovr-core.js"></script>
</body>
</html>
```

`defaultContents:true` together with `physics:true` is what brings in the demo ramps and ball — swap those out for your own `physx-body` entities once you've confirmed physics is working (see the `DiscoVR` class's `addEntity()` for adding arbitrary components like `physx-body`).

## Embedded widget

A small, non-VR scene meant to sit inside an iframe or a section of a larger page — no VR button, drag instead of pointer-lock to look around.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Embedded Widget</title>
</head>
<body>
    <discovr
        presets="defaultScene:true;defaultLights:true"
        environment="preset:default"
        interface="vrButton:false;embedded:true"
    ></discovr>

    <script type="module" src="https://core.discovr-engine.eu/discovr-core.js"></script>
</body>
</html>
```

## Product viewer (orbit camera)

A product or 3D configurator page. There is no walking: the camera orbits the object (drag to rotate, wheel or pinch to zoom), and a slow turntable runs until the visitor touches it. `i-orbit-camera` needs a `camera` on the same entity, and that entity's position is where the view starts.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Product Viewer</title>
</head>
<body>
    <discovr interface="vrButton:false"></discovr>

    <a-scene>
        <a-assets>
            <a-asset-item id="productModel" src="product.glb"></a-asset-item>
        </a-assets>
        <a-entity id="product" gltf-model="#productModel"></a-entity>
        <a-entity light="type: ambient; intensity: 0.6"></a-entity>
        <a-entity light="type: directional; intensity: 0.8" position="2 4 3"></a-entity>
        <a-entity camera="active: true" position="0 1.4 3"
                  i-orbit-camera="target: #product; minDistance: 1; maxDistance: 6; autoRotate: true"></a-entity>
    </a-scene>

    <script type="module" src="https://core.discovr-engine.eu/discovr-core.js"></script>
</body>
</html>
```

## Product configurator (variants)

The product viewer above, with options the visitor can switch. Each `i-variant__<name>` is one choice of one option group. A choice can change the colour, texture (`map`), `metalness` or `roughness` of glTF `materials` or `nodes`, and can `show` or `hide` parts. With `xray: on` (or `off`) a choice switches the model's x-ray view, on the nodes listed in `xrayNodes` (empty = the whole model), with the look of the model's own `i-xray` settings. `i-configurator-ui` on the scene lists the groups as a panel.

The current choice of a group is the bus topic `variant:<group>`, so the options can also be changed from a script, for example `DiscoVR.bus.set("variant:fabric", "Blue")`, or from an `i-bus` rule.

```html
<a-scene i-configurator-ui="title: Configure your chair; position: right; theme: dark">
    <a-assets>
        <a-asset-item id="chairModel" src="chair.glb"></a-asset-item>
        <a-asset-item id="linen" src="linen.jpg"></a-asset-item>
    </a-assets>
    <a-entity id="chair" gltf-model="#chairModel"
        i-variant__red="group: fabric; groupLabel: Fabric; label: Red; initial: true; materials: Fabric; color: #b3261e"
        i-variant__blue="group: fabric; label: Blue; materials: Fabric; color: #1e4fb3"
        i-variant__linen="group: fabric; label: Linen; materials: Fabric; color: #ffffff; map: #linen"
        i-variant__arms="group: arms; groupLabel: Armrests; label: With; initial: true; show: Arms"
        i-variant__noarms="group: arms; label: Without; hide: Arms"
        i-variant__outside="group: view; groupLabel: View; label: Outside; initial: true"
        i-variant__inside="group: view; label: Inside; xray: on; xrayNodes: Shell; show: Frame"></a-entity>
    <a-entity camera="active: true" position="0 1.2 2.5" i-orbit-camera="target: #chair; autoRotate: true"></a-entity>
</a-scene>
```

### Sharing and embedding a configurator

`i-configurator-api` on the scene connects the configurator to the outside:

- With `url: true`, the visitor's choices are kept in the page address, for example `?variant.fabric=Linen&variant.arms=Without`. That makes the configuration a link that can be shared. A link with those parameters opens with the same choices.
- With `embed: true`, a page that shows the configurator in an `<iframe>` can control it through `postMessage`.
- `i-configurator-ui` can also show "Copy link" and "Download image" buttons, with `share: true` and `download: true`.
- The visitor can fold the panel from its header, so it doesn't cover the model. `collapsed` sets how it opens: `auto` (the default: folded when the scene is narrower than 600px, as on a phone), `open` or `closed`.

```html
<a-scene i-configurator-ui="title: Configure your chair; share: true; download: true"
         i-configurator-api="url: true; embed: true; origins: https://shop.example.com">
```

The page that embeds it:

```html
<iframe id="viewer" src="https://example.com/p/my-chair"></iframe>
<script>
  const viewer = document.getElementById("viewer");
  window.addEventListener("message", (e) => {
    if (e.source !== viewer.contentWindow) return;
    // {type: "discovr:ready", groups, state}, then {type: "discovr:change", group, label, state}
    // {type: "discovr:state", requestId, state, groups} / {type: "discovr:screenshot", requestId, dataUrl}
    console.log(e.data);
  });
  viewer.contentWindow.postMessage({ type: "discovr:select", group: "fabric", label: "Blue" }, "*");
  viewer.contentWindow.postMessage({ type: "discovr:getState", requestId: 1 }, "*");
  viewer.contentWindow.postMessage({ type: "discovr:screenshot", requestId: 2, mimeType: "image/png" }, "*");
</script>
```

`origins` lists the pages allowed to talk to the configurator. `*`, or leaving it empty, allows any page.

