# Image Target Video Gallery With Button Interaction

**URL:** <https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595>\
**Category:** Technical Support\
**Tags:** image-targets\
**Created:** [November 15, 2024, 6:49am UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595 "2024-11-15T06:49:06Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Irving\_Mercado](https://avatars.discourse-cdn.com/v4/letter/i/48db29/32.png) [@Irving\_Mercado](https://forum.8thwall.com/u/Irving_Mercado)\
**Post date:** [November 15, 2024, 6:49am UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/1 "2024-11-15T06:49:06Z")

</div>

Hello, Fairly new to 8th wall. I want to create a **video gallery overlaying an image target**. The functionality I’m aiming for includes:

1. When the image target is detected, an **initial video** plays automatically, overlaying the target.
2. The user can interact with **buttons** displayed in the AR scene. Each button corresponds to a specific video.
3. When a button is clicked:

- The **initial video stops and is replaced** by the video corresponding to the clicked button.
- The new video should then play, still overlaying the same image target.

The key challenge I’m facing is getting the initial video to **stop and become invisible** when the new video is triggered, while ensuring a seamless transition between videos.

I’ve tried approaches such as hiding the initial video using CSS (`display: none`) or using A-Frame attributes (`visible`), but I’m struggling to make it work consistently with `xrextras-target-video-sound`. Additionally, I attempted swapping between two separate image target entities but ran into difficulties managing visibility and playback states.

Does anyone have suggestions for managing video swapping while maintaining a smooth user experience? I’d appreciate insights, best practices, or example code!

---

<div class="post-metadata">

**Author:** ![GeorgeButler](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.8thwall.com/georgebutler/32/1903_2.png) [@GeorgeButler](https://forum.8thwall.com/u/GeorgeButler)\
**Post date:** [November 15, 2024, 9:59pm UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/2 "2024-11-15T21:59:30Z")

</div>

Hi, Welcome to the forums!

Would you be able to post a video of the current behavior along with the code?

---

<div class="post-metadata">

**Author:** ![Irving\_Mercado](https://avatars.discourse-cdn.com/v4/letter/i/48db29/32.png) [@Irving\_Mercado](https://forum.8thwall.com/u/Irving_Mercado)\
**Post date:** [November 15, 2024, 11:33pm UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/3 "2024-11-15T23:33:04Z")

</div>

Hey George,

Thank you in advance for your help here!

[Here](https://www.youtube.com/shorts/zyUqhISxWAA) is a link to a screen recording. In the recording, I alternate between clicking the two buttons. When I click the “Start Video Button”, the experience works as intended. However, when I click the “Video 1 Button”, the audio of the corresponding video starts playing, but the video itself is not visible. Additionally, the “Start Video” pauses and remains visible. My ultimate goal here is to have 6 buttons allowing the user to cycle seamlessly through 6 different videos.

Below is the code:

```auto
app.js

// Import components and primitives
import { myNamedImageTargetComponent, namedImageTargetPrimitive } from './my-named-target';

// Register component
AFRAME.registerComponent('my-xrextras-named-imagetarget', myNamedImageTargetComponent);
AFRAME.registerPrimitive('my-xrextras-named-image-target', namedImageTargetPrimitive);

// Component to handle video playback on button click
AFRAME.registerComponent('play-video', {
  schema: { videoId: { type: 'string' } }, // ID of the video to play

  init: function () {
    this.el.addEventListener('click', () => {
      const videoId = this.data.videoId; // Get the video ID from schema
      const videoPlayer = document.querySelector('#video-player'); // Get the video player element
      const videoElement = document.querySelector(videoId); // Get the actual video element by ID

      if (!videoElement) {
        console.error(`Video with ID ${videoId} not found.`);
        return;
      }

      // Pause and reset the currently playing video if any
      const currentVideoId = videoPlayer.getAttribute('video');
      if (currentVideoId) {
        const currentVideoElement = document.querySelector(currentVideoId);
        if (currentVideoElement) {
          currentVideoElement.pause();
          currentVideoElement.currentTime = 0; // Reset to the beginning
        }
      }

      // Update the video source in xrextras-target-video-sound component
      videoPlayer.setAttribute('src', videoElement.getAttribute('src'));

      // Trigger the new video to play directly
      videoElement.play();

      // Manually trigger xrextras-target-video-sound component to reload the video source
      videoPlayer.components['xrextras-target-video-sound'].play();
    });
  },
});

console.log('App.js loaded and initialized.');

body.html

<a-scene
  device-orientation
  xrextras-gesture-detector
  landing-page
  xrextras-loading="
    loadBackgroundColor: #63ACA8;
    cameraBackgroundColor: #63ACA8;
    loadImage: #logo-icon;
    loadAnimation: pulse"
  xrextras-runtime-error
  renderer="colorManagement:true"
  xrweb="disableWorldTracking: true">

  <!-- Assets -->
  <a-assets>
    <img id="start-thumb" src="assets/start-thumbnail.jpg">
    <img id="logo-icon" src="./assets/logo-icon.png">

    <!-- Video Assets for the Gallery -->
    <video id="start-video" crossorigin="anonymous" loop="false" src="assets/start-video.mp4"></video>
    <video id="video-1" crossorigin="anonymous" loop="false" src="assets/video-1.mp4"></video>
  </a-assets>

  <!-- Camera and Lights -->
  <a-camera position="0 0 0" raycaster="objects: .cantap" cursor="fuse: false; rayOrigin: mouse;"></a-camera>
  <a-light type="directional" intensity="0.5" position="1 1 1"></a-light>
  <a-light type="ambient" intensity="0.7"></a-light>

  <!-- Image Target with Video -->
  <my-xrextras-named-image-target name="start-target">
    <xrextras-target-video-sound 
      video="#start-video" 
      thumb="#start-thumb" 
      height="1" 
      width="1.1" 
      id="video-player">
    </xrextras-target-video-sound>

   <!-- Buttons as part of the tracked entity -->
    <a-entity position="0 -1 0" id="button-container" visible="true">
     
  <a-plane
    position="-0.5 0 0"
    width="0.5"
    height="0.2"
    color="#63ACA8"
    class="cantap"
    text="value: Start Video; color: #F3EBCE; align: center; width: 4;"
    play-video="videoId: #start-video">
  </a-plane>

  <a-plane
    position="0.5 0 0"
    width="0.5"
    height="0.2"
    color="#63ACA8"
    class="cantap"
    text="value: Video 1; color: #F3EBCE; align: center; width: 4;"
    play-video="videoId: #video-1">
  </a-plane>

    </a-entity>
  </my-xrextras-named-image-target>

  </my-xrextras-named-image-target>

</a-scene>

my-named-target.js

const myNamedImageTargetComponent = {
  schema: {
    name: { type: 'string' },
  },
  init() {
    const { object3D } = this.el;
    const { name } = this.data;
    const geometry = {};

    const onready = () => {
      this.el.sceneEl.removeEventListener('realityready', onready);
      object3D.visible = false;
    };

    this.el.sceneEl.addEventListener('realityready', onready);

    const checkGeometry = (newGeometry) => {
      let needsUpdate = false;
      const fields = [
        'type',
        'height',
        'radiusTop',
        'radiusBottom',
        'arcLengthRadians',
        'arcStartRadians',
        'scaledWidth',
        'scaledHeight',
      ];

      fields.forEach((f) => {
        if (geometry[f] !== newGeometry[f]) {
          geometry[f] = newGeometry[f];
          needsUpdate = true;
        }
      });

      if (needsUpdate) {
        this.el.emit('xrextrasimagegeometry', geometry, false);
      }
    };

    const imageScanning = ({ detail }) => {
      detail.imageTargets.forEach((t) => {
        if (name !== t.name) return;
        checkGeometry({ type: t.type, ...t.geometry });
      });
    };

    const updateImage = ({ detail }) => {
      if (name !== detail.name) return;
      object3D.position.copy(detail.position);
      object3D.quaternion.copy(detail.rotation);
      object3D.scale.set(detail.scale, detail.scale, detail.scale);
      object3D.visible = true;
    };

    const showImage = ({ detail }) => {
      if (name !== detail.name) return;
      checkGeometry(detail);
      updateImage({ detail });
      this.el.emit('xrextrasfound', {}, false);
    };

    const hideImage = ({ detail }) => {
      if (name !== detail.name) return;
      this.el.emit('xrextraslost', {}, false);
      object3D.visible = false;
    };

    this.el.sceneEl.addEventListener('xrimagescanning', imageScanning);
    this.el.sceneEl.addEventListener('xrimagefound', showImage);
    this.el.sceneEl.addEventListener('xrimageupdated', updateImage);
    this.el.sceneEl.addEventListener('xrimagelost', hideImage);
  },
};

const namedImageTargetPrimitive = {
  defaultComponents: {
    'my-xrextras-named-imagetarget': {},
  },
  mappings: {
    name: 'my-xrextras-named-imagetarget.name',
  },
};

export { myNamedImageTargetComponent, namedImageTargetPrimitive };

```

---

<div class="post-metadata">

**Author:** ![GeorgeButler](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.8thwall.com/georgebutler/32/1903_2.png) [@GeorgeButler](https://forum.8thwall.com/u/GeorgeButler)\
**Post date:** [November 18, 2024, 5:19pm UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/4 "2024-11-18T17:19:21Z")

</div>

Can you share your project with [support@8thwall.com](mailto:support@8thwall.com)?

---

<div class="post-metadata">

**Author:** ![Irving\_Mercado](https://avatars.discourse-cdn.com/v4/letter/i/48db29/32.png) [@Irving\_Mercado](https://forum.8thwall.com/u/Irving_Mercado)\
**Post date:** [November 20, 2024, 5:28am UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/5 "2024-11-20T05:28:05Z")

</div>

Just shared!

Thank you for your time.

---

<div class="post-metadata">

**Author:** ![Irving\_Mercado](https://avatars.discourse-cdn.com/v4/letter/i/48db29/32.png) [@Irving\_Mercado](https://forum.8thwall.com/u/Irving_Mercado)\
**Post date:** [November 27, 2024, 7:19am UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/6 "2024-11-27T07:19:24Z")

</div>

Hey @GeorgeButler, Just wanted to see if you were able to get access to the project?

Thank you!

---

<div class="post-metadata">

**Author:** ![GeorgeButler](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.8thwall.com/georgebutler/32/1903_2.png) [@GeorgeButler](https://forum.8thwall.com/u/GeorgeButler)\
**Post date:** [December 2, 2024, 4:46pm UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/7 "2024-12-02T16:46:13Z")

</div>

Hey Irving!

Thanks for the patience! Our office just returned from a Holiday. Can you share it with the `support` workspace? It’s the same process just without the email address part.

---

<div class="post-metadata">

**Author:** ![Irving\_Mercado](https://avatars.discourse-cdn.com/v4/letter/i/48db29/32.png) [@Irving\_Mercado](https://forum.8thwall.com/u/Irving_Mercado)\
**Post date:** [December 2, 2024, 6:16pm UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/8 "2024-12-02T18:16:54Z")

</div>

Thanks @GeorgeButler! Just sent an invite to share with support.

---

<div class="post-metadata">

**Author:** ![GeorgeButler](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.8thwall.com/georgebutler/32/1903_2.png) [@GeorgeButler](https://forum.8thwall.com/u/GeorgeButler)\
**Post date:** [December 2, 2024, 6:17pm UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/9 "2024-12-02T18:17:27Z")

</div>

Got it, I’ll take a look.

---

<div class="post-metadata">

**Author:** ![Irving\_Mercado](https://avatars.discourse-cdn.com/v4/letter/i/48db29/32.png) [@Irving\_Mercado](https://forum.8thwall.com/u/Irving_Mercado)\
**Post date:** [December 12, 2024, 5:27pm UTC](https://forum.8thwall.com/t/image-target-video-gallery-with-button-interaction/3595/10 "2024-12-12T17:27:16Z")

</div>

Hey @GeorgeButler, Just checking to see if you might have had a chance to take a look here. Thank you!
