@needle-tools/engine 4.14.0 → 4.15.0-next.cecd8e7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/components.needle.json +1 -1
  3. package/dist/{needle-engine.bundle-NolzHLqO.min.js → needle-engine.bundle-CuAiLb-d.min.js} +137 -129
  4. package/dist/{needle-engine.bundle-COL2Bar3.umd.cjs → needle-engine.bundle-JQGIFVRm.umd.cjs} +128 -120
  5. package/dist/{needle-engine.bundle-Z_gAD7Kg.js → needle-engine.bundle-VZVrVbc3.js} +5497 -5252
  6. package/dist/needle-engine.d.ts +318 -42
  7. package/dist/needle-engine.js +570 -569
  8. package/dist/needle-engine.min.js +1 -1
  9. package/dist/needle-engine.umd.cjs +1 -1
  10. package/lib/engine/engine_accessibility.d.ts +77 -0
  11. package/lib/engine/engine_accessibility.js +162 -0
  12. package/lib/engine/engine_accessibility.js.map +1 -0
  13. package/lib/engine/engine_context.d.ts +2 -0
  14. package/lib/engine/engine_context.js +7 -0
  15. package/lib/engine/engine_context.js.map +1 -1
  16. package/lib/engine/engine_materialpropertyblock.d.ts +90 -4
  17. package/lib/engine/engine_materialpropertyblock.js +97 -7
  18. package/lib/engine/engine_materialpropertyblock.js.map +1 -1
  19. package/lib/engine/engine_math.d.ts +34 -1
  20. package/lib/engine/engine_math.js +34 -1
  21. package/lib/engine/engine_math.js.map +1 -1
  22. package/lib/engine/engine_networking.js +1 -1
  23. package/lib/engine/engine_networking.js.map +1 -1
  24. package/lib/engine/engine_types.d.ts +2 -0
  25. package/lib/engine/engine_types.js +2 -0
  26. package/lib/engine/engine_types.js.map +1 -1
  27. package/lib/engine/webcomponents/icons.js +3 -0
  28. package/lib/engine/webcomponents/icons.js.map +1 -1
  29. package/lib/engine/webcomponents/logo-element.d.ts +1 -0
  30. package/lib/engine/webcomponents/logo-element.js +3 -1
  31. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  32. package/lib/engine/webcomponents/needle-button.d.ts +37 -11
  33. package/lib/engine/webcomponents/needle-button.js +42 -11
  34. package/lib/engine/webcomponents/needle-button.js.map +1 -1
  35. package/lib/engine/webcomponents/needle-engine.d.ts +10 -2
  36. package/lib/engine/webcomponents/needle-engine.js +13 -3
  37. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  38. package/lib/engine-components/Component.d.ts +1 -2
  39. package/lib/engine-components/Component.js +1 -2
  40. package/lib/engine-components/Component.js.map +1 -1
  41. package/lib/engine-components/DragControls.d.ts +1 -0
  42. package/lib/engine-components/DragControls.js +21 -0
  43. package/lib/engine-components/DragControls.js.map +1 -1
  44. package/lib/engine-components/NeedleMenu.d.ts +2 -0
  45. package/lib/engine-components/NeedleMenu.js +2 -0
  46. package/lib/engine-components/NeedleMenu.js.map +1 -1
  47. package/lib/engine-components/Networking.d.ts +28 -3
  48. package/lib/engine-components/Networking.js +28 -3
  49. package/lib/engine-components/Networking.js.map +1 -1
  50. package/lib/engine-components/ReflectionProbe.d.ts +1 -0
  51. package/lib/engine-components/ReflectionProbe.js +20 -2
  52. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  53. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +15 -0
  54. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +77 -0
  55. package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
  56. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  57. package/lib/engine-components/ui/Button.d.ts +1 -0
  58. package/lib/engine-components/ui/Button.js +11 -0
  59. package/lib/engine-components/ui/Button.js.map +1 -1
  60. package/lib/engine-components/ui/Text.d.ts +1 -0
  61. package/lib/engine-components/ui/Text.js +11 -0
  62. package/lib/engine-components/ui/Text.js.map +1 -1
  63. package/package.json +2 -2
  64. package/src/engine/engine_accessibility.ts +198 -0
  65. package/src/engine/engine_context.ts +9 -0
  66. package/src/engine/engine_materialpropertyblock.ts +102 -11
  67. package/src/engine/engine_math.ts +34 -1
  68. package/src/engine/engine_networking.ts +1 -1
  69. package/src/engine/engine_types.ts +5 -0
  70. package/src/engine/webcomponents/icons.ts +3 -0
  71. package/src/engine/webcomponents/logo-element.ts +4 -1
  72. package/src/engine/webcomponents/needle-button.ts +44 -13
  73. package/src/engine/webcomponents/needle-engine.ts +18 -7
  74. package/src/engine-components/Component.ts +1 -3
  75. package/src/engine-components/DragControls.ts +29 -4
  76. package/src/engine-components/NeedleMenu.ts +5 -3
  77. package/src/engine-components/Networking.ts +29 -4
  78. package/src/engine-components/ReflectionProbe.ts +21 -2
  79. package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +108 -32
  80. package/src/engine-components/ui/Button.ts +12 -0
  81. package/src/engine-components/ui/Text.ts +13 -0
@@ -13,12 +13,11 @@ import { AudioSource } from "../../../../AudioSource.js";
13
13
  import { Behaviour, GameObject } from "../../../../Component.js";
14
14
  import { Rigidbody } from "../../../../RigidBody.js";
15
15
  import type { IPointerClickHandler, PointerEventData } from "../../../../ui/PointerEvents.js";
16
-
17
- import { makeNameSafeForUSD,USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
16
+ import { makeNameSafeForUSD, USDDocument, USDObject, USDZExporterContext } from "../../ThreeUSDZExporter.js";
18
17
  import { AnimationExtension, RegisteredAnimationInfo, type UsdzAnimation } from "../Animation.js";
19
18
  import { AudioExtension } from "./AudioExtension.js";
20
19
  import type { BehaviorExtension, UsdzBehaviour } from "./Behaviour.js";
21
- import { ActionBuilder, ActionModel, BehaviorModel, EmphasizeActionMotionType,GroupActionModel,type IBehaviorElement, Target, TriggerBuilder } from "./BehavioursBuilder.js";
20
+ import { ActionBuilder, ActionModel, BehaviorModel, EmphasizeActionMotionType, GroupActionModel, type IBehaviorElement, Target, TriggerBuilder } from "./BehavioursBuilder.js";
22
21
 
23
22
  const debug = getParam("debugusdzbehaviours");
24
23
 
@@ -57,6 +56,22 @@ export class ChangeTransformOnClick extends Behaviour implements IPointerClickHa
57
56
  private targetRot = new Quaternion();
58
57
  private targetScale = new Vector3();
59
58
 
59
+ onEnable(): void {
60
+ this.context.accessibility.updateElement(this, {
61
+ role: "button",
62
+ label: "Move " + (this.object?.name || "object") + " to " + (this.target?.name || "target") + " on click",
63
+ hidden: false,
64
+ })
65
+ }
66
+ onDisable(): void {
67
+ this.context.accessibility.updateElement(this, {
68
+ hidden: true,
69
+ });
70
+ }
71
+ onDestroy(): void {
72
+ this.context.accessibility.removeElement(this);
73
+ }
74
+
60
75
  onPointerEnter() {
61
76
  this.context.input.setCursor("pointer");
62
77
  }
@@ -68,8 +83,8 @@ export class ChangeTransformOnClick extends Behaviour implements IPointerClickHa
68
83
 
69
84
  const rbs = this.object?.getComponentsInChildren(Rigidbody);
70
85
 
71
- if (rbs){
72
- for (const rb of rbs) {
86
+ if (rbs) {
87
+ for (const rb of rbs) {
73
88
  rb.resetVelocities();
74
89
  rb.resetForcesAndTorques();
75
90
  }
@@ -227,6 +242,22 @@ export class ChangeMaterialOnClick extends Behaviour implements IPointerClickHan
227
242
  }
228
243
  }
229
244
 
245
+ onEnable(): void {
246
+ this.context.accessibility.updateElement(this, {
247
+ role: "button",
248
+ label: "Change material to " + (this.variantMaterial?.name || "unknown material"),
249
+ hidden: false,
250
+ })
251
+ }
252
+ onDisable(): void {
253
+ this.context.accessibility.updateElement(this, {
254
+ hidden: true,
255
+ });
256
+ }
257
+ onDestroy(): void {
258
+ this.context.accessibility.removeElement(this);
259
+ }
260
+
230
261
  onPointerEnter(_args: PointerEventData) {
231
262
  this.context.input.setCursor("pointer");
232
263
  }
@@ -427,7 +458,7 @@ export class SetActiveOnClick extends Behaviour implements IPointerClickHandler,
427
458
 
428
459
  if (!this.toggleOnClick && this.hideSelf)
429
460
  this.gameObject.visible = false;
430
-
461
+
431
462
  if (this.target)
432
463
  this.target.visible = this.toggleOnClick ? !this.target.visible : this.targetState;
433
464
  }
@@ -453,7 +484,7 @@ export class SetActiveOnClick extends Behaviour implements IPointerClickHandler,
453
484
 
454
485
  beforeCreateDocument() {
455
486
  if (!this.target) return;
456
-
487
+
457
488
  // need to cache on the object itself, because otherwise different actions would override each other's visibility state
458
489
  // TODO would probably be better to have this somewhere on the exporter, not on this component
459
490
  if (this.gameObject[SetActiveOnClick.wasVisible] === undefined)
@@ -514,7 +545,7 @@ export class SetActiveOnClick extends Behaviour implements IPointerClickHandler,
514
545
  // It's much easier to reason about nested actions when we're not duplicating tons of hierarchy...
515
546
  // We can probably only do a shallow clone when the tapped object has geometry of its own, otherwise
516
547
  // we end up with nothing to tap on.
517
-
548
+
518
549
  // Option A: we deep clone ourselves. This makes hierarchical cases and nested behaviours really complex.
519
550
  // We do this currently when the object doesn't have any geometry.
520
551
  if (!this.selfModelClone.geometry) {
@@ -533,11 +564,11 @@ export class SetActiveOnClick extends Behaviour implements IPointerClickHandler,
533
564
  clone.name += "_toggle" + (SetActiveOnClick.clonedToggleIndex++);
534
565
  originalModel.add(clone);
535
566
  this.gameObject[SetActiveOnClick.toggleClone] = clone;
536
-
567
+
537
568
  console.warn("USDZExport: Toggle " + this.gameObject.name + " doesn't have geometry. It will be deep cloned and nested behaviours will likely not work.");
538
569
  }
539
570
  const clonedSelfModel = this.gameObject[SetActiveOnClick.toggleClone];
540
-
571
+
541
572
  if (!this.gameObject[SetActiveOnClick.reverseToggleClone]) {
542
573
  const clone = this.selfModelClone.clone();
543
574
  clone.setMatrix(new Matrix4());
@@ -589,7 +620,7 @@ export class SetActiveOnClick extends Behaviour implements IPointerClickHandler,
589
620
  TriggerBuilder.tapTrigger(selfModel),
590
621
  ActionBuilder.parallel(...toggleSequence)
591
622
  ));
592
-
623
+
593
624
  const reverseSequence: ActionModel[] = [];
594
625
  reverseSequence.push(ActionBuilder.fadeAction(this.toggleModel, 0, false));
595
626
  reverseSequence.push(ActionBuilder.fadeAction(selfModel, 0, true));
@@ -680,7 +711,7 @@ export class HideOnStart extends Behaviour implements UsdzBehaviour {
680
711
  }
681
712
 
682
713
  private wasVisible: boolean = false;
683
-
714
+
684
715
  beforeCreateDocument() {
685
716
  this.wasVisible = GameObject.isActiveSelf(this.gameObject);
686
717
  }
@@ -713,6 +744,22 @@ export class EmphasizeOnClick extends Behaviour implements UsdzBehaviour {
713
744
  @serializable()
714
745
  motionType: EmphasizeActionMotionType = "bounce";
715
746
 
747
+ onEnable(): void {
748
+ this.context.accessibility.updateElement(this, {
749
+ role: "button",
750
+ label: "Emphasize " + this.target?.name + " on click",
751
+ hidden: false,
752
+ })
753
+ }
754
+ onDisable(): void {
755
+ this.context.accessibility.updateElement(this, {
756
+ hidden: true,
757
+ });
758
+ }
759
+ onDestroy(): void {
760
+ this.context.accessibility.removeElement(this);
761
+ }
762
+
716
763
  beforeCreateDocument() { }
717
764
 
718
765
  createBehaviours(ext, model, _context) {
@@ -775,6 +822,21 @@ export class PlayAudioOnClick extends Behaviour implements IPointerClickHandler,
775
822
  }
776
823
  }
777
824
 
825
+ onEnable(): void {
826
+ this.context.accessibility.updateElement(this, {
827
+ role: "button",
828
+ label: "Play audio: " + (this.clip || this.target?.clip || "unknown clip"),
829
+ hidden: false,
830
+ })
831
+ }
832
+ onDisable(): void {
833
+ this.context.accessibility.updateElement(this, {
834
+ hidden: true,
835
+ });
836
+ }
837
+ onDestroy(): void {
838
+ this.context.accessibility.removeElement(this);
839
+ }
778
840
 
779
841
  onPointerEnter() {
780
842
  this.context.input.setCursor("pointer");
@@ -816,7 +878,7 @@ export class PlayAudioOnClick extends Behaviour implements IPointerClickHandler,
816
878
  const clipName = AudioExtension.getName(clipUrl);
817
879
  const volume = this.target ? this.target.volume : 1;
818
880
  const auralMode = this.target && this.target.spatialBlend == 0 ? "nonSpatial" : "spatial";
819
-
881
+
820
882
  // This checks if any child is clickable – if yes, the tap trigger is added; if not, we omit it.
821
883
  let anyChildHasGeometry = false;
822
884
  this.gameObject.traverse(c => {
@@ -825,7 +887,7 @@ export class PlayAudioOnClick extends Behaviour implements IPointerClickHandler,
825
887
  // Workaround: seems iOS often simply doesn't play audio on scene start when this is NOT present.
826
888
  // unclear why, but having a useless tap action (nothing to tap on) "fixes" it.
827
889
  anyChildHasGeometry = true;
828
-
890
+
829
891
  const audioClip = ext.addAudioClip(clipUrl);
830
892
  // const stopAction: IBehaviorElement = ActionBuilder.playAudioAction(playbackTarget, audioClip, "stop", volume, auralMode);
831
893
  let playAction: IBehaviorElement = ActionBuilder.playAudioAction(playbackTarget, audioClip, "play", volume, auralMode);
@@ -834,8 +896,7 @@ export class PlayAudioOnClick extends Behaviour implements IPointerClickHandler,
834
896
 
835
897
  const behaviorName = (this.name ? "_" + this.name : "");
836
898
 
837
- if (anyChildHasGeometry && this.trigger === "tap")
838
- {
899
+ if (anyChildHasGeometry && this.trigger === "tap") {
839
900
  // does not seem to work in iOS / QuickLook...
840
901
  // TODO use play "type" which can be start/stop/pause
841
902
  if (this.toggleOnClick) (playAction as ActionModel).multiplePerformOperation = "stop";
@@ -901,9 +962,25 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
901
962
 
902
963
  private get target() { return this.animator?.gameObject || this.animation?.gameObject }
903
964
 
965
+ onEnable(): void {
966
+ this.context.accessibility.updateElement(this, {
967
+ role: "button",
968
+ label: "Plays animation " + (this.stateName || "") + " on " + (this.target ? this.target.name : ""),
969
+ hidden: false
970
+ });
971
+ }
972
+ onDisable(): void {
973
+ this.context.accessibility.updateElement(this, {
974
+ hidden: true,
975
+ });
976
+ }
977
+ onDestroy(): void {
978
+ this.context.accessibility.removeElement(this);
979
+ }
904
980
 
905
981
  onPointerEnter() {
906
982
  this.context.input.setCursor("pointer");
983
+ this.context.accessibility.hover(this, "Click to play animation " + (this.stateName || "") + " on " + (this.target ? this.target.name : ""));
907
984
  }
908
985
  onPointerExit() {
909
986
  this.context.input.unsetCursor("pointer");
@@ -912,6 +989,7 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
912
989
  args.use();
913
990
  if (!this.target) return;
914
991
  if (this.stateName) {
992
+ this.context.accessibility.focus(this);
915
993
  // TODO this is currently quite annoying to use,
916
994
  // as for the web we use the Animator component and its states directly,
917
995
  // while in QuickLook we use explicit animations / states.
@@ -923,8 +1001,8 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
923
1001
 
924
1002
  private stateAnimationModel: any;
925
1003
 
926
- private animationSequence? = new Array<RegisteredAnimationInfo>();
927
- private animationLoopAfterSequence? = new Array<RegisteredAnimationInfo>();
1004
+ private animationSequence?= new Array<RegisteredAnimationInfo>();
1005
+ private animationLoopAfterSequence?= new Array<RegisteredAnimationInfo>();
928
1006
  private randomOffsetNormalized: number = 0;
929
1007
 
930
1008
  createBehaviours(_ext: BehaviorExtension, model: USDObject, _context: USDZExporterContext) {
@@ -950,9 +1028,9 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
950
1028
  afterCreateDocument(ext: BehaviorExtension, context: USDZExporterContext) {
951
1029
  if ((this.animationSequence === undefined && this.animationLoopAfterSequence === undefined) || !this.stateAnimationModel) return;
952
1030
  if (!this.target) return;
953
-
1031
+
954
1032
  const document = context.document;
955
-
1033
+
956
1034
  // check if the AnimationExtension has been attached and what data it has for the current object
957
1035
  const animationExt = context.extensions.find(ext => ext instanceof AnimationExtension) as AnimationExtension;
958
1036
  if (!animationExt) return;
@@ -966,7 +1044,7 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
966
1044
  if (requiresExclusivePlayback) {
967
1045
  if (isDevEnvironment())
968
1046
  console.warn("Setting exclusive playback for " + this.target.name + "@" + this.stateName + " because it has " + animationExt.getClipCount(this.target) + " animations. This works around QuickLook bug FB13410767.");
969
-
1047
+
970
1048
  PlayAnimationOnClick.rootsWithExclusivePlayback.add(this.target);
971
1049
  }
972
1050
 
@@ -986,7 +1064,7 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
986
1064
  this.trigger == "tap" ? TriggerBuilder.tapTrigger(this.selfModel) : TriggerBuilder.sceneStartTrigger(),
987
1065
  sequence
988
1066
  );
989
-
1067
+
990
1068
  // See comment above for why exclusive playback is currently required when playing multiple animations on the same root.
991
1069
  if (requiresExclusivePlayback)
992
1070
  playAnimationOnTap.makeExclusive(true);
@@ -1008,8 +1086,7 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
1008
1086
 
1009
1087
  const sequence = ActionBuilder.sequence();
1010
1088
 
1011
- if (animationSequence && animationSequence.length > 0)
1012
- {
1089
+ if (animationSequence && animationSequence.length > 0) {
1013
1090
  for (const anim of animationSequence) {
1014
1091
  sequence.addAction(getOrCacheAction(model, anim));
1015
1092
  }
@@ -1033,11 +1110,10 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
1033
1110
  return sequence;
1034
1111
  }
1035
1112
 
1036
- static getAndRegisterAnimationSequences(ext: AnimationExtension, target: GameObject, stateName?: string):
1037
- {
1038
- animationSequence: Array<RegisteredAnimationInfo>,
1113
+ static getAndRegisterAnimationSequences(ext: AnimationExtension, target: GameObject, stateName?: string): {
1114
+ animationSequence: Array<RegisteredAnimationInfo>,
1039
1115
  animationLoopAfterSequence: Array<RegisteredAnimationInfo>,
1040
- randomTimeOffset: number,
1116
+ randomTimeOffset: number,
1041
1117
  } | undefined {
1042
1118
 
1043
1119
  if (!target) return undefined;
@@ -1055,14 +1131,14 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
1055
1131
  let animationLoopAfterSequence: Array<RegisteredAnimationInfo> = [];
1056
1132
 
1057
1133
  if (animation) {
1058
- const anim = ext.registerAnimation(target, animation.clip);
1059
- if (anim) {
1134
+ const anim = ext.registerAnimation(target, animation.clip);
1135
+ if (anim) {
1060
1136
  if (animation.loop)
1061
1137
  animationLoopAfterSequence.push(anim);
1062
1138
  else
1063
1139
  animationSequence.push(anim);
1064
1140
  }
1065
-
1141
+
1066
1142
  let randomTimeOffset = 0;
1067
1143
  if (animation.minMaxOffsetNormalized) {
1068
1144
  const from = animation.minMaxOffsetNormalized.x;
@@ -1156,7 +1232,7 @@ export class PlayAnimationOnClick extends Behaviour implements IPointerClickHand
1156
1232
  if (lastClip) {
1157
1233
  let clipCopy: AnimationClip | undefined;
1158
1234
  if (ext.holdClipMap.has(lastClip)) {
1159
- clipCopy = ext.holdClipMap.get(lastClip);
1235
+ clipCopy = ext.holdClipMap.get(lastClip);
1160
1236
  }
1161
1237
  else {
1162
1238
  // We're creating a "hold" clip here; exactly 1 second long, and inteprolates exactly on the duration of the clip
@@ -180,6 +180,8 @@ export class Button extends Behaviour implements IPointerEventHandler {
180
180
  this.onClick.invoke();
181
181
  args.use();
182
182
 
183
+ this.context.accessibility.focus(this);
184
+
183
185
  // debug clicks for WebXR
184
186
  if (debug) {
185
187
  const pos = this.gameObject.worldPosition;
@@ -238,9 +240,19 @@ export class Button extends Behaviour implements IPointerEventHandler {
238
240
 
239
241
  onEnable() {
240
242
  super.onEnable();
243
+ this.context.accessibility.updateElement(this, {
244
+ role: "button",
245
+ label: this.gameObject.name + " button",
246
+ hidden: false
247
+ });
248
+ }
249
+ onDisable() {
250
+ super.onDisable();
251
+ this.context.accessibility.updateElement(this, { hidden: true })
241
252
  }
242
253
 
243
254
  onDestroy(): void {
255
+ this.context.accessibility.removeElement(this);
244
256
  if (this._isHovered) this.context.input.unsetCursor("pointer");
245
257
  }
246
258
 
@@ -102,6 +102,7 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
102
102
  this._text = val;
103
103
  this.feedText(this.text, this.supportRichText);
104
104
  this.markDirty();
105
+ this.context.accessibility.updateElement(this, { label: this.text });
105
106
  }
106
107
  }
107
108
 
@@ -238,6 +239,13 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
238
239
 
239
240
  onEnable(): void {
240
241
  super.onEnable();
242
+
243
+ this.context.accessibility.updateElement(this, {
244
+ role: "text",
245
+ label: this.text,
246
+ hidden: false
247
+ });
248
+
241
249
  this._didHandleTextRenderOnTop = false;
242
250
  if (this.uiObject) {
243
251
  // @ts-ignore
@@ -261,6 +269,11 @@ export class Text extends Graphic implements IHasAlphaFactor, ICanvasEventReceiv
261
269
  onDisable(): void {
262
270
  super.onDisable();
263
271
  this.canvas?.unregisterEventReceiver(this);
272
+ this.context.accessibility.updateElement(this, { hidden: true });
273
+ }
274
+ onDestroy(): void {
275
+ super.onDestroy();
276
+ this.context.accessibility.removeElement(this);
264
277
  }
265
278
 
266
279
  private getAlignment(opts: ThreeMeshUIEveryOptions): ThreeMeshUIEveryOptions {