webgpu/Outlines throws on every construction
Writing the first-ever story for this component surfaced it immediately. Reproduced in the story suite on v11-working:
TypeError: Cannot set properties of undefined (setting 'value')
❯ set opacity src/webgpu/Effects/Outlines/Outlines.tsx:151:23
❯ new OutlinesMaterial src/webgpu/Effects/Outlines/Outlines.tsx:64:4
❯ src/webgpu/Effects/Outlines/Outlines.tsx:188:42
Cause
OutlinesMaterial declares an accessor pair:
set opacity(v: number) {
this._opacityValue.value = v
}
Accessors live on the prototype, so they exist before the constructor body runs. super() invokes three's Material constructor, which assigns this.opacity = 1 — and that dispatches straight into the subclass setter, while this._opacityValue = uniform(1.0) is still two lines away in the constructor body.
Deterministic. No GPU needed. It fires on every construction.
This is the same root cause as #2765 (MeshPortalMaterial throws under /webgpu: "accessors run before their uniforms exist"). Two components, one bug shape — worth checking every NodeMaterial subclass in src/webgpu/ that pairs a uniform field with an accessor of a name three's Material constructor also assigns (opacity, transparent, side, visible, color on the basic materials).
Why nothing caught it
React swallows the throw into "An error occurred in the <CanvasImpl> component", so the story still counts as passing. The component was one of the 12 that had never been rendered by anyone, which is why a crash this deterministic survived.
Fix shape
Either initialise the uniform fields before anything can dispatch to the setter, or make the setter tolerate a not-yet-constructed uniform. Given #2765 is the same bug, whichever pattern is chosen should be applied to both and written down.
Found while writing stories for #2801.
webgpu/Outlinesthrows on every constructionWriting the first-ever story for this component surfaced it immediately. Reproduced in the story suite on
v11-working:Cause
OutlinesMaterialdeclares an accessor pair:Accessors live on the prototype, so they exist before the constructor body runs.
super()invokes three'sMaterialconstructor, which assignsthis.opacity = 1— and that dispatches straight into the subclass setter, whilethis._opacityValue = uniform(1.0)is still two lines away in the constructor body.Deterministic. No GPU needed. It fires on every construction.
This is the same root cause as #2765 (
MeshPortalMaterialthrows under/webgpu: "accessors run before their uniforms exist"). Two components, one bug shape — worth checking everyNodeMaterialsubclass insrc/webgpu/that pairs a uniform field with an accessor of a name three'sMaterialconstructor also assigns (opacity,transparent,side,visible,coloron the basic materials).Why nothing caught it
React swallows the throw into "An error occurred in the
<CanvasImpl>component", so the story still counts as passing. The component was one of the 12 that had never been rendered by anyone, which is why a crash this deterministic survived.Fix shape
Either initialise the uniform fields before anything can dispatch to the setter, or make the setter tolerate a not-yet-constructed uniform. Given #2765 is the same bug, whichever pattern is chosen should be applied to both and written down.
Found while writing stories for #2801.