How to set the image of a UI Element in script?

I have a very simple question: I don’t know how to correctly set the image of a UI Element at runtime.

First of all, am I correct to plug my initial image asset into the Color value of the Background property? That’s the only way that seems afforded by Studio to set an image reference for the UI Element. Did I miss something?

Secondly, what is the proper API syntax to change this at runtime? In a Custom Component that is attached to my UI Element, inside of a method defined inside of the default state of stateMachine definition block that is listening for click, I have

ecs.Ui.set(world, eid, {
  image: './assets/panels/2.png'
})

(I have uploaded 20 PNG files to a subdirectory in the project called panels, to be clear.)

When I trigger the logic inside the method from clicking on the image, I get validation that it is firing off from incrementing an int in the data definition and printing a message to the console, but the image mapped to the UI element is not working.

I’m not getting any linter / syntax errors from this call, but my image reference is not changing on click. What am I missing? Should I perhaps try this with a Plane’s Color parameter on an unlit material instead?

Thanks :folded_hands: I have intentions to build really neat web app with this and I have been looking forward to embracing both WebXR and Niantic Studio for some time. It’s looking like I can do everything I need this app to do, I just REALLY need to get the hang of this TypeScript API.

Have you tried mutate:

  ecs.Ui.mutate(world, eid, (cursor) => {
  cursor.textureSrc =  "./assets/panels/2.png';
  return false;
  })
1 Like

If the asset is in your assets folder you should be using the absolute path:

assets/panels/2.png

1 Like

Hi @Pete_Collins @GeorgeButler , thanks for the suggestions.
Unfortunately neither of these worked.

re: mutate, I am seeing the method fire off from printing to console, but textureSrc is a property of Materials and not UI Elements, so I replaced it with image.

re: file path, I am not seeing any evidence otherwise that using the convention assets/panels/2.png vs ./assets/panels/2.png will work. All other suggestions on this forum use the ./ convention. Furthermore the IDE autocompletes with the ./assets/panels/N.png convention. Regardless, neither option works.

I have attached a screenshot of my Editor with as much of the contextual information as I can cram into one image. I left both the mutate and set approaches uncommented in the image but, you know, either or would otherwise be used.

Thank you for any additional insight you can provide! :folded_hands:

It doesn’t look like you’re setting it in the right place. Add an onEnter() to your ‘default’ state and add there i.e.

ecs.defineState(‘default’)
.initial()
.onEnter(() => {
const {materialMe} = schemaAttribute.get(eid)
ecs.Material.mutate(world, materialMe, (cursor) => {
cursor.textureSrc = “assets/ship_000.png”;
return false;
})
})

1 Like

I made a really simple repro component and I was able to flip between images. :slight_smile:

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

ecs.registerComponent({
  name: 'Flipbook',
  schema: {
  },
  schemaDefaults: {
  },
  data: {
    frame: ecs.i32,
  },
  stateMachine: ({world, eid, schemaAttribute, dataAttribute}) => {
    const frames = [
      '',
      'assets/1.png',
      'assets/2.png',
      'assets/3.png',
    ]

    dataAttribute.set(eid, {
      frame: 0,
    })

    ecs.defineState('default')
      .initial()
      .listen(eid, ecs.input.UI_CLICK, () => {
        dataAttribute.mutate(eid, (c) => {
          c.frame = Math.min(c.frame + 1, frames.length - 1)
        })

        ecs.Ui.set(world, eid, {
          image: `${frames[dataAttribute.get(eid).frame]}`,
        })

        console.log(ecs.Ui.get(world, eid).image)
      })
  },
})
1 Like

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.