Trigger animation by tapping 3D model

I’m working on a VPS project where I’d like to trigger a position and scale animation when a specific 3D model is tapped. I’ve tried grabbing a component from the Hotspots example project, which I intended to modify (I’ve added it below), however I keep getting the following error: “Unhandled promise rejection: Error: Failed to establish cursor”. I’m not sure what it means. Maybe there’s a better way to achieve this? Having a button as a trigger would be ok too, though I’d prefer tapping the 3D model.

import * as ecs from '@8thwall/ecs'

ecs.registerComponent({
  name: 'Hotspot',
  schema: {
    // @required
    uiElement: ecs.eid,
    speed: ecs.i32,
    highlightedSpeed: ecs.i32,
    // @group start Default Color:color
    r: ecs.f32,
    g: ecs.f32,
    b: ecs.f32,
    // @group end
    // @group start Highlighted Color:color
    highlightedR: ecs.f32,
    highlightedG: ecs.f32,
    highlightedB: ecs.f32,
    // @group end
  },
  schemaDefaults: {
    speed: 5000,
    highlightedSpeed: 1500,
    r: 174,
    g: 0,
    b: 255,
    highlightedR: 255,
    highlightedG: 0,
    highlightedB: 255,
  },
  stateMachine: ({world, eid, schemaAttribute}) => {
    ecs.defineState('idle')
      .initial()
      .onEnter(() => {
        const {speed, r, g, b, uiElement} = schemaAttribute.get(eid)

        ecs.Material.mutate(world, eid, (cursor) => {
          cursor.r = r
          cursor.g = g
          cursor.b = b
        })

        ecs.RotateAnimation.set(world, eid, {
          loop: true,
          autoFrom: true,
          toY: 360,
          shortestPath: false,
          duration: speed,
        })

        ecs.LookAtAnimation.set(world, uiElement, {
          target: world.camera.getActiveEid(),
        })

        ecs.Hidden.set(world, uiElement, {})
      })
      .listen(eid, ecs.input.SCREEN_TOUCH_START, (e) => {
        world.events.dispatch(world.events.globalId, 'hotspot_activated', {
        // @ts-ignore
          eid: e.data.target,
        })
      })
      .listen(world.events.globalId, 'hotspot_activated', (e) => {
        const {uiElement, r, g, b, highlightedR, highlightedG, highlightedB, speed, highlightedSpeed} = schemaAttribute.get(eid)

        // @ts-ignore
        if (e.data.eid === eid) {
          ecs.RotateAnimation.mutate(world, eid, (cursor) => {
            cursor.duration = highlightedSpeed
          })

          ecs.Material.mutate(world, eid, (cursor) => {
            cursor.r = highlightedR
            cursor.g = highlightedG
            cursor.b = highlightedB
          })

          ecs.Hidden.remove(world, uiElement)
        } else {
          ecs.RotateAnimation.mutate(world, eid, (cursor) => {
            cursor.duration = speed
          })

          ecs.Material.mutate(world, eid, (cursor) => {
            cursor.r = r
            cursor.g = g
            cursor.b = b
          })

          ecs.Hidden.set(world, uiElement, {})
        }
      })
  },
})

I would do it something like this:

import * as ecs from '@8thwall/ecs'

ecs.registerComponent({
  name: 'Tap Grow',
  stateMachine: ({world, eid, schemaAttribute, dataAttribute}) => {
    ecs.defineState('default')
      .initial()
      .onEvent(ecs.input.SCREEN_TOUCH_START, 'clicked')

    ecs.defineState('clicked')
      .onEnter(() => {
        ecs.ScaleAnimation.set(world, eid, {
          autoFrom: true,
          toX: 2,
          toY: 2,
          toZ: 2,
          easeOut: true,
          easingFunction: 'Elastic',
          loop: false,
        })

        ecs.PositionAnimation.set(world, eid, {
          autoFrom: true,
          toX: 0,
          toY: 1,
          toZ: 0,
          loop: false,
        })
      })
  },
})

Thanks, George. For some reason this isn’t working for me, can you tell me if I’ve set it up correctly?

Actually, I figured it out - deleting the previous version of the 3D model called “sleeping_dog.glb” made it work. I assume because it was in the same position in the scene, it was receiving the clicks instead of “sleeping_dog_2.glb”. Though I thought hiding it would make it inactive in the scene, is that a misunderstanding on my part?

Hiding and Disabled are two different things. The Eye icon :eye: hides objects but they still exist, the checkbox :check_box_with_check: will actually disable the object so its not created in the scene.

Ah, that clears things up, thanks!