# Custom studio ui coaching overlay

**URL:** <https://forum.8thwall.com/t/custom-studio-ui-coaching-overlay/8526>\
**Category:** Technical Support\
**Created:** [November 9, 2025, 11:32am UTC](https://forum.8thwall.com/t/custom-studio-ui-coaching-overlay/8526 "2025-11-09T11:32:57Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Philip\_Johansen](https://avatars.discourse-cdn.com/v4/letter/p/96bed5/32.png) [@Philip\_Johansen](https://forum.8thwall.com/u/Philip_Johansen)\
**Post date:** [November 9, 2025, 11:32am UTC](https://forum.8thwall.com/t/custom-studio-ui-coaching-overlay/8526/1 "2025-11-09T11:32:58Z")

</div>

I’m trying to make some code where I have a Studio UI with an image that guides the user.  
I want it to hide the UI when the image target is found, and show it again when the image target disappears.  
However, I can’t get this code to work — it doesn’t hide the UI when the image target is detected.

import \* as ecs from ‘[@8thwall](https://forum.8thwall.com/groups/8thwall)/ecs’

// Store handlers per component instance (keyed by component EID)  
const onFoundMap = new Map\<bigint, (ev: any) =\> void\>()  
const onLostMap = new Map\<bigint, (ev: any) =\> void\>()

ecs.registerComponent({  
name: ‘XR Image Probe’,  
schema: {  
// @label UI Entity to toggle while scanning  
uiEntity: ecs.eid, // eid = bigint  
// @label Filter by target name (empty = any)  
targetName: ecs.string,  
// @label Start visible (true = show until FOUND)  
startVisible: ecs.boolean,  
},  
// Keep data empty to avoid type constraints entirely  
data: {},

add: (world, c) =\> {  
const s = c.schemaAttribute as any

```auto
const ui = (s.uiEntity as unknown) as bigint | undefined

const setHidden = (eid: bigint | undefined, hidden: boolean) => {
  if (typeof eid !== 'bigint') return
  hidden ? ecs.Hidden.set(world, eid, {}) : ecs.Hidden.remove(world, eid)
}

const startVisible = typeof s.startVisible === 'boolean' ? s.startVisible : true
setHidden(ui, !startVisible)

const matches = (name: string) => {
  const filter = (s.targetName ?? '').trim()
  return !filter || filter === name
}

const onFound = (ev: any) => {
  const name = ev?.data?.name as string
  if (matches(name)) setHidden(ui, true)
}
const onLost = (ev: any) => {
  const name = ev?.data?.name as string
  if (matches(name)) setHidden(ui, false)
}

const gid = world.events.globalId as unknown as bigint
world.events.addListener(gid, (ecs.events as any).REALITY_IMAGE_FOUND, onFound)
world.events.addListener(gid, (ecs.events as any).REALITY_IMAGE_LOST, onLost)

// Save handlers for cleanup by this component instance
const key = c.eid as unknown as bigint
onFoundMap.set(key, onFound)
onLostMap.set(key, onLost)

```

},

remove: (world, c) =\> {  
const gid = world.events.globalId as unknown as bigint  
const key = c.eid as unknown as bigint

```auto
const onFound = onFoundMap.get(key)
const onLost = onLostMap.get(key)

if (onFound) world.events.removeListener(gid, (ecs.events as any).REALITY_IMAGE_FOUND, onFound)
if (onLost) world.events.removeListener(gid, (ecs.events as any).REALITY_IMAGE_LOST, onLost)

onFoundMap.delete(key)
onLostMap.delete(key)

```

},  
})

---

<div class="post-metadata">

**Author:** ![Evan](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.8thwall.com/evan/32/431_2.png) [@Evan](https://forum.8thwall.com/u/Evan)\
**Post date:** [December 5, 2025, 7:23pm UTC](https://forum.8thwall.com/t/custom-studio-ui-coaching-overlay/8526/2 "2025-12-05T19:23:30Z")

</div>

have you tried adding console.logs throughout your code? this could help narrow down the issue. i.e. is onLost / onFound being called when you expect?
