entity-a and entity-b resolve through getEntity, which returns null for a reference that names nothing live. pc-joint passes that null straight to the engine component, which declines to create a constraint. Nothing is reported, so the joint just does not exist — and since a joint has no visual of its own, the only symptom is that two bodies move independently. That is indistinguishable from a physics problem, which is where the debugging time goes.
Where it bites
The reference need not be wrong. It resolves once, when it is assigned, and a pc-node has no entity until its container asset has loaded — so this is silent and empty:
<pc-entity name="knee">
<pc-joint type="hinge" entity-a="#shin" entity-b="#thigh"></pc-joint>
</pc-entity>
<pc-model asset="robot">
<pc-node id="shin" name="shin_l"><pc-rigidbody type="dynamic"></pc-rigidbody></pc-node>
<pc-node id="thigh" name="thigh_l"><pc-rigidbody type="dynamic"></pc-rigidbody></pc-node>
</pc-model>
Hit while building the ragdoll example in #388. The workaround there was to nest each joint inside the pc-node it drives, which is a better pattern anyway — a pc-node's children are built once it has bound, so the references resolve — but nothing pointed at it, and nothing said the first attempt had failed.
This is deliberate
Worth being explicit, because it changes the question from "fix an oversight" to "revisit a decision". The current behaviour is pinned by a test in test/integration/components/joint-component.test.ts:
it('leaves an unresolvable reference null without warning', ...)
// No warning claimed here: getEntity resolves references quietly, and the guard fails the test if anything warns
There is a plausible reason for it. The documented recovery is to assign the attribute again once the target exists, so an author who builds a scene from script may legitimately set a reference before its target is there, and a warning at that moment would be noise.
Against that: sibling elements already report exactly this class of mistake, and loudly. pc-model warns for an asset id that resolves to nothing (pc-model could not find asset 'x' - model not created). pc-node warns for a name it cannot find, for an ambiguous one, and for a duplicate binding — it even offers the closest match by edit distance and exposes the outcome as state. Against that backdrop pc-joint's silence reads as an inconsistency rather than a policy.
Two failures, two fixes
If this is reported, the cause matters, because the remedies are opposite:
- Nothing in the document matches the reference. Usually a typo or a missing element. Fix the reference.
- Something matches but is not backing an entity. Usually timing — the
pc-node case above — or pointing at the wrong element entirely. The reference may be perfectly correct.
getEntity currently collapses both into null. Distinguishing them needs the matched element, which means splitting the element lookup out of getEntity.
Scope
Five components resolve references this way: pc-joint, pc-button (image-entity), pc-scrollbar (handle-entity), pc-scrollview (viewport-entity, content-entity, the scrollbars) and pc-script (entity: attribute values). They all fail the same silent way. Worth deciding whether this is a pc-joint fix or a shared one — pc-joint is only the most punishing case, because the others usually have some visible consequence.
Options
- Warn on a non-empty reference that does not resolve, naming which of the two causes it hit. Non-breaking, no timing change. Accepts the false positive on the documented "assign it again later" pattern, which the message can turn into guidance rather than noise.
- Warn only if it is still unresolved a frame later. Removes that false positive at the cost of a deferred, slightly less predictable message.
- Re-resolve automatically when the referenced element becomes ready, and warn only if it never does. Fixes the underlying problem rather than reporting it, and
pc-node already has the machinery (it follows its host's ready events). But it changes when references resolve, so it wants more care than a diagnostic — and it is the one option that could surprise existing code.
- Expose the outcome as state, as
pc-node does, so a document's wiring can be asserted programmatically rather than only observed in the console.
An empty reference should stay silent under any of these: on entity-b it is the documented way to pin the first body to a point in world space, and on either it is the transient state of an element whose reference has yet to be assigned.
Happy to put up a PR for whichever direction is preferred. I have (1) implemented on a local branch, including the split of findEntityElement out of getEntity and updated tests, if that is the one worth having.
entity-aandentity-bresolve throughgetEntity, which returnsnullfor a reference that names nothing live.pc-jointpasses thatnullstraight to the engine component, which declines to create a constraint. Nothing is reported, so the joint just does not exist — and since a joint has no visual of its own, the only symptom is that two bodies move independently. That is indistinguishable from a physics problem, which is where the debugging time goes.Where it bites
The reference need not be wrong. It resolves once, when it is assigned, and a
pc-nodehas no entity until its container asset has loaded — so this is silent and empty:Hit while building the ragdoll example in #388. The workaround there was to nest each joint inside the
pc-nodeit drives, which is a better pattern anyway — apc-node's children are built once it has bound, so the references resolve — but nothing pointed at it, and nothing said the first attempt had failed.This is deliberate
Worth being explicit, because it changes the question from "fix an oversight" to "revisit a decision". The current behaviour is pinned by a test in
test/integration/components/joint-component.test.ts:There is a plausible reason for it. The documented recovery is to assign the attribute again once the target exists, so an author who builds a scene from script may legitimately set a reference before its target is there, and a warning at that moment would be noise.
Against that: sibling elements already report exactly this class of mistake, and loudly.
pc-modelwarns for an asset id that resolves to nothing (pc-model could not find asset 'x' - model not created).pc-nodewarns for a name it cannot find, for an ambiguous one, and for a duplicate binding — it even offers the closest match by edit distance and exposes the outcome asstate. Against that backdroppc-joint's silence reads as an inconsistency rather than a policy.Two failures, two fixes
If this is reported, the cause matters, because the remedies are opposite:
pc-nodecase above — or pointing at the wrong element entirely. The reference may be perfectly correct.getEntitycurrently collapses both intonull. Distinguishing them needs the matched element, which means splitting the element lookup out ofgetEntity.Scope
Five components resolve references this way:
pc-joint,pc-button(image-entity),pc-scrollbar(handle-entity),pc-scrollview(viewport-entity,content-entity, the scrollbars) andpc-script(entity:attribute values). They all fail the same silent way. Worth deciding whether this is apc-jointfix or a shared one —pc-jointis only the most punishing case, because the others usually have some visible consequence.Options
pc-nodealready has the machinery (it follows its host'sreadyevents). But it changes when references resolve, so it wants more care than a diagnostic — and it is the one option that could surprise existing code.pc-nodedoes, so a document's wiring can be asserted programmatically rather than only observed in the console.An empty reference should stay silent under any of these: on
entity-bit is the documented way to pin the first body to a point in world space, and on either it is the transient state of an element whose reference has yet to be assigned.Happy to put up a PR for whichever direction is preferred. I have (1) implemented on a local branch, including the split of
findEntityElementout ofgetEntityand updated tests, if that is the one worth having.