Repository navigation
Description
XrInputSource#elementEntity is documented as the "entity with Element component at which this input source is hovering" and typed Entity|null, but ElementInput stores the hovered ElementComponent in it. Code that follows the docs or the TypeScript type breaks at runtime: elementEntity.name is undefined and elementEntity.getPosition() throws. Only a null check works either way.
Where
- The docs and type: , emitted as
engine/src/framework/xr/xr-input-source.js
Lines 439 to 447 in 6767f25
/** * If {@link elementInput} is true, this property will hold entity with Element * component at which this input source is hovering, or null if not hovering over any element. * * @type {Entity|null} */ get elementEntity() { return this._elementEntity; } get elementEntity(): Entity | nullin playcanvas.d.ts - The assignment: .
engine/src/framework/input/element-input.js
Line 859 in 6767f25
inputSource._elementEntity = element || null; elementcomes from_getTargetElementByRay, which returns one of theElementComponents registered withaddElement().engine/src/framework/input/element-input.js
Lines 512 to 516 in 6767f25
addElement(element) { if (this._elements.indexOf(element) === -1) { this._elements.push(element); } }
Both date from #1988 (2020), which documented the property as a pc.Entity.
Repro
On the null device, with the fake WebXR session from test/framework/xr/fake-webxr.mjs, I set up a world-space screen with one useInput image element (button), an ElementInput, and a controller whose ray points at the element. After one XR frame:
| Check | Result |
|---|---|
inputSource.elementEntity instanceof Entity |
false |
inputSource.elementEntity === button.element |
true |
inputSource.elementEntity.entity === button |
true |
inputSource.elementEntity.name |
undefined |
inputSource.elementEntity.getPosition() |
TypeError: ... getPosition is not a function |
In a browser, any XR session with world-space UI shows the same:
app.xr.input.on('selectstart', (inputSource) => {
console.log(inputSource.elementEntity); // an ElementComponent while over UI
});Nothing in the engine, its examples or scripts/esm reads the property. The user manual repeats the documented contract on UI in XR ("The entity of the element that this input source points at") and Input Sources ("read its elementEntity for the entity of the element it points at").
Fix
There are two options:
- Store
element.entity, which matches the name, the docs, the type and the manual. This changes the value for anyone relying on the component today (theirelementEntity.entitywould becomeundefined), so it needs a release note. - Keep the value and change the docs and type to
ElementComponent|null. The name would stay misleading, and the manual would need updating.
A test that points an input source's ray at an element and checks elementEntity would pin either choice.
Found in passing while auditing the XR scripts in scripts/esm/xr.
Activity