@zylem/behaviors 0.3.0 → 0.4.0

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 (169) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{behavior-system-DYbx-x_-.d.ts → behavior-system-DSNek0W9.d.ts} +205 -29
  3. package/dist/{chunk-RER2IDPW.js → chunk-4URF65BR.js} +1 -0
  4. package/dist/chunk-4URF65BR.js.map +1 -0
  5. package/dist/{chunk-YYJP62QD.js → chunk-4V7TIRO2.js} +1 -0
  6. package/dist/chunk-4V7TIRO2.js.map +1 -0
  7. package/dist/{chunk-F7E23E26.js → chunk-4WH2ZN7P.js} +1 -0
  8. package/dist/chunk-4WH2ZN7P.js.map +1 -0
  9. package/dist/{chunk-VPZ32CCD.js → chunk-5SM5SH5O.js} +29 -28
  10. package/dist/chunk-5SM5SH5O.js.map +1 -0
  11. package/dist/{chunk-L76JG73P.js → chunk-5XZWTFGF.js} +7 -4
  12. package/dist/chunk-5XZWTFGF.js.map +1 -0
  13. package/dist/{chunk-HIBJDA5Z.js → chunk-64HKCSXD.js} +21 -17
  14. package/dist/chunk-64HKCSXD.js.map +1 -0
  15. package/dist/{chunk-WSKD7GY3.js → chunk-7JJEIADR.js} +1 -0
  16. package/dist/chunk-7JJEIADR.js.map +1 -0
  17. package/dist/{chunk-F6LFX4V3.js → chunk-BXP4K7RF.js} +3 -2
  18. package/dist/chunk-BXP4K7RF.js.map +1 -0
  19. package/dist/{chunk-2HKY6WF7.js → chunk-EIWQM6U3.js} +1 -0
  20. package/dist/chunk-EIWQM6U3.js.map +1 -0
  21. package/dist/{chunk-YDLO5M7S.js → chunk-EZNCCO4L.js} +1 -0
  22. package/dist/chunk-EZNCCO4L.js.map +1 -0
  23. package/dist/{chunk-T2P4JTQN.js → chunk-FRJDQM23.js} +110 -155
  24. package/dist/chunk-FRJDQM23.js.map +1 -0
  25. package/dist/{chunk-FHDYJ5WP.js → chunk-FTDZAKZW.js} +5 -17
  26. package/dist/chunk-FTDZAKZW.js.map +1 -0
  27. package/dist/{chunk-D53GNZXP.js → chunk-GFARAJV2.js} +6 -7
  28. package/dist/chunk-GFARAJV2.js.map +1 -0
  29. package/dist/{chunk-IQRG5BAZ.js → chunk-GTLA6LOJ.js} +18 -23
  30. package/dist/chunk-GTLA6LOJ.js.map +1 -0
  31. package/dist/{chunk-VO5J64DG.js → chunk-H4TJ7X4O.js} +4 -6
  32. package/dist/chunk-H4TJ7X4O.js.map +1 -0
  33. package/dist/{chunk-6UMC6BB5.js → chunk-HNESASBB.js} +7 -8
  34. package/dist/chunk-HNESASBB.js.map +1 -0
  35. package/dist/{chunk-4DVDFCVY.js → chunk-HZMY3TT4.js} +1 -0
  36. package/dist/chunk-HZMY3TT4.js.map +1 -0
  37. package/dist/{chunk-2HLZBWGD.js → chunk-IZJFUAXB.js} +1 -0
  38. package/dist/chunk-IZJFUAXB.js.map +1 -0
  39. package/dist/{chunk-UFHYR2LV.js → chunk-JXMF4NUI.js} +51 -2
  40. package/dist/chunk-JXMF4NUI.js.map +1 -0
  41. package/dist/{chunk-ZHBD65AZ.js → chunk-KDY5N6J4.js} +1 -0
  42. package/dist/chunk-KDY5N6J4.js.map +1 -0
  43. package/dist/chunk-KFFETUAL.js +40 -0
  44. package/dist/chunk-KFFETUAL.js.map +1 -0
  45. package/dist/chunk-LL4FLHIY.js +12 -0
  46. package/dist/chunk-LL4FLHIY.js.map +1 -0
  47. package/dist/{chunk-BC3IJYS7.js → chunk-MJFMNRMZ.js} +15 -15
  48. package/dist/chunk-MJFMNRMZ.js.map +1 -0
  49. package/dist/{chunk-WHKPWIQO.js → chunk-OHCPV2NT.js} +1 -0
  50. package/dist/chunk-OHCPV2NT.js.map +1 -0
  51. package/dist/{chunk-RQWWUML4.js → chunk-OTLSUYQQ.js} +2 -1
  52. package/dist/chunk-OTLSUYQQ.js.map +1 -0
  53. package/dist/{chunk-E4HTCQPK.js → chunk-PWF757B6.js} +7 -8
  54. package/dist/chunk-PWF757B6.js.map +1 -0
  55. package/dist/{chunk-4EWASZHB.js → chunk-QVCMJ4Q2.js} +1 -0
  56. package/dist/chunk-QVCMJ4Q2.js.map +1 -0
  57. package/dist/{chunk-FOOM42MK.js → chunk-RONH2KDI.js} +12 -13
  58. package/dist/chunk-RONH2KDI.js.map +1 -0
  59. package/dist/chunk-RTRFJVCZ.js +454 -0
  60. package/dist/chunk-RTRFJVCZ.js.map +1 -0
  61. package/dist/{chunk-IEA7F73P.js → chunk-UL6Q5HDP.js} +25 -2
  62. package/dist/chunk-UL6Q5HDP.js.map +1 -0
  63. package/dist/{chunk-K6CWKFHL.js → chunk-UYFOLI2X.js} +1 -0
  64. package/dist/chunk-UYFOLI2X.js.map +1 -0
  65. package/dist/{chunk-RD2YTTXY.js → chunk-V74N7D6Q.js} +9 -8
  66. package/dist/chunk-V74N7D6Q.js.map +1 -0
  67. package/dist/{chunk-ERS6SNA5.js → chunk-WOMHL23C.js} +2 -1
  68. package/dist/chunk-WOMHL23C.js.map +1 -0
  69. package/dist/{chunk-RHW3IDQX.js → chunk-WWVD5DR5.js} +1 -0
  70. package/dist/chunk-WWVD5DR5.js.map +1 -0
  71. package/dist/{chunk-SBACY5SU.js → chunk-WXXXJ22R.js} +14 -15
  72. package/dist/chunk-WXXXJ22R.js.map +1 -0
  73. package/dist/{chunk-6Y3GB76J.js → chunk-XLUJDKCT.js} +9 -8
  74. package/dist/chunk-XLUJDKCT.js.map +1 -0
  75. package/dist/{chunk-7Y6JVZ5H.js → chunk-XP3ASVGJ.js} +14 -10
  76. package/dist/chunk-XP3ASVGJ.js.map +1 -0
  77. package/dist/{chunk-7U4WFBWM.js → chunk-Y7YIAWPW.js} +11 -0
  78. package/dist/chunk-Y7YIAWPW.js.map +1 -0
  79. package/dist/{chunk-7IZ36Y5G.js → chunk-ZA43LPRM.js} +5 -24
  80. package/dist/chunk-ZA43LPRM.js.map +1 -0
  81. package/dist/{chunk-J5XLB24H.js → chunk-ZRQWSURL.js} +3 -2
  82. package/dist/chunk-ZRQWSURL.js.map +1 -0
  83. package/dist/cooldown.d.ts +2 -1
  84. package/dist/cooldown.js +3 -2
  85. package/dist/cooldown.js.map +1 -0
  86. package/dist/coordinators/boundary-ricochet-3d.d.ts +12 -5
  87. package/dist/coordinators/boundary-ricochet-3d.js +4 -2
  88. package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
  89. package/dist/coordinators/boundary-ricochet.d.ts +9 -7
  90. package/dist/coordinators/boundary-ricochet.js +4 -2
  91. package/dist/coordinators/boundary-ricochet.js.map +1 -0
  92. package/dist/coordinators/first-person-shooter.d.ts +9 -8
  93. package/dist/coordinators/first-person-shooter.js +4 -3
  94. package/dist/coordinators/first-person-shooter.js.map +1 -0
  95. package/dist/coordinators/multidirectional-space-shooter.d.ts +12 -9
  96. package/dist/coordinators/multidirectional-space-shooter.js +5 -4
  97. package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
  98. package/dist/coordinators/top-down-shooter.d.ts +9 -8
  99. package/dist/coordinators/top-down-shooter.js +5 -4
  100. package/dist/coordinators/top-down-shooter.js.map +1 -0
  101. package/dist/core.d.ts +4 -4
  102. package/dist/core.js +9 -36
  103. package/dist/core.js.map +1 -0
  104. package/dist/destructible-3d.d.ts +2 -1
  105. package/dist/destructible-3d.js +4 -3
  106. package/dist/destructible-3d.js.map +1 -0
  107. package/dist/destructible-prebake.js +2 -1
  108. package/dist/destructible-prebake.js.map +1 -0
  109. package/dist/first-person.d.ts +12 -12
  110. package/dist/first-person.js +12 -11
  111. package/dist/first-person.js.map +1 -0
  112. package/dist/index.d.ts +37 -14
  113. package/dist/index.js +85 -55
  114. package/dist/index.js.map +1 -0
  115. package/dist/jumper-2d.d.ts +7 -6
  116. package/dist/jumper-2d.js +8 -7
  117. package/dist/jumper-2d.js.map +1 -0
  118. package/dist/jumper-3d.d.ts +12 -11
  119. package/dist/jumper-3d.js +9 -8
  120. package/dist/jumper-3d.js.map +1 -0
  121. package/dist/{moveable-BCRpjAQb.d.ts → moveable-BLTHO7Jq.d.ts} +2 -78
  122. package/dist/particle-emitter/presets.js +2 -1
  123. package/dist/particle-emitter/presets.js.map +1 -0
  124. package/dist/particle-emitter.d.ts +1 -1
  125. package/dist/particle-emitter.js +5 -4
  126. package/dist/particle-emitter.js.map +1 -0
  127. package/dist/platformer-2d.d.ts +306 -0
  128. package/dist/platformer-2d.js +23 -0
  129. package/dist/platformer-2d.js.map +1 -0
  130. package/dist/platformer-3d.d.ts +74 -87
  131. package/dist/platformer-3d.js +7 -6
  132. package/dist/platformer-3d.js.map +1 -0
  133. package/dist/ricochet-2d.d.ts +1 -1
  134. package/dist/ricochet-2d.js +5 -4
  135. package/dist/ricochet-2d.js.map +1 -0
  136. package/dist/ricochet-3d.d.ts +1 -1
  137. package/dist/ricochet-3d.js +5 -4
  138. package/dist/ricochet-3d.js.map +1 -0
  139. package/dist/runtime-2d.d.ts +93 -2
  140. package/dist/runtime-2d.js +146 -22
  141. package/dist/runtime-2d.js.map +1 -0
  142. package/dist/screen-visibility.d.ts +2 -1
  143. package/dist/screen-visibility.js +3 -2
  144. package/dist/screen-visibility.js.map +1 -0
  145. package/dist/screen-wrap.d.ts +2 -1
  146. package/dist/screen-wrap.js +5 -4
  147. package/dist/screen-wrap.js.map +1 -0
  148. package/dist/shooter-2d.d.ts +5 -3
  149. package/dist/shooter-2d.js +5 -4
  150. package/dist/shooter-2d.js.map +1 -0
  151. package/dist/shooter-fire-DGripl0z.d.ts +55 -0
  152. package/dist/thruster.d.ts +8 -18
  153. package/dist/thruster.js +9 -8
  154. package/dist/thruster.js.map +1 -0
  155. package/dist/top-down-movement.d.ts +7 -4
  156. package/dist/top-down-movement.js +8 -7
  157. package/dist/top-down-movement.js.map +1 -0
  158. package/dist/{use-behavior-D_82jAL3.d.ts → use-behavior-h9-T5FSv.d.ts} +1 -1
  159. package/dist/world-boundary-2d.d.ts +2 -1
  160. package/dist/world-boundary-2d.js +6 -5
  161. package/dist/world-boundary-2d.js.map +1 -0
  162. package/dist/world-boundary-3d.d.ts +2 -1
  163. package/dist/world-boundary-3d.js +6 -5
  164. package/dist/world-boundary-3d.js.map +1 -0
  165. package/package.json +8 -7
  166. package/dist/chunk-23HQH3GJ.js +0 -34
  167. package/dist/chunk-K4UBXSZL.js +0 -175
  168. package/dist/runtime-pong.d.ts +0 -92
  169. package/dist/runtime-pong.js +0 -37
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts","../src/lib/physics/physics-pose.ts","../src/lib/behaviors/destructible-3d/index.ts"],"sourcesContent":["import {\n\tActiveCollisionTypes,\n\tColliderDesc,\n\tRigidBodyDesc,\n} from '@dimforge/rapier3d-compat';\nimport {\n\tDestructibleMesh,\n\tFractureOptions as PinataFractureOptions,\n} from '@dgreenheck/three-pinata';\nimport {\n\tBox3,\n\tBufferAttribute,\n\tBufferGeometry,\n\tGroup,\n\tMatrix4,\n\tQuaternion,\n\tVector2,\n\tVector3,\n\ttype Material,\n\ttype Mesh,\n\ttype Object3D,\n} from 'three';\n\nimport * as Comlink from 'comlink';\n\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport type { CreateEntityFn, GameEntity } from '../../entities/entity';\nimport { getBodyRenderPose } from '../../physics/physics-pose';\n\nimport {\n\tbuildFractureGeometryCacheKey,\n\tbuildNormalizedFractureSourceGeometry,\n\tbufferGeometryToPlain,\n\ttype DestructiblePrebakeWorkerAPI,\n\tpinataFractureOptionsToPlain,\n\tplainWorkerResultToTemplateParts,\n} from '../../destructible-prebake';\n\nexport type FractureOptionsInput =\n\tNonNullable<ConstructorParameters<typeof PinataFractureOptions>[0]>;\n\nexport type Destructible3DFragmentColliderShape =\n\t| 'convexHull'\n\t| 'cuboid'\n\t| 'trimesh';\n\nexport interface Destructible3DColliderOptions {\n\tshape?: Destructible3DFragmentColliderShape;\n\tsensor?: boolean;\n\tcollisionGroups?: number;\n\tactiveCollisionTypes?: number;\n}\n\nexport interface Destructible3DFragmentPhysicsOptions {\n\tmode?: 'compound' | 'independent';\n\tinheritSourceVelocity?: boolean;\n\toutwardVelocity?: number;\n\tangularVelocity?: number;\n}\n\nexport interface Destructible3DBehaviorOptions {\n\tfractureOptions?: FractureOptionsInput | PinataFractureOptions;\n\tinnerMaterial?: Material | null;\n\tcollider?: Destructible3DColliderOptions;\n\tfragmentPhysics?: Destructible3DFragmentPhysicsOptions;\n\t/**\n\t * When set, {@link Destructible3DHandle.prebakeAsync} runs Voronoi fracture\n\t * in a Web Worker (see `destructible-prebake-worker` bundle).\n\t */\n\tprebakeWorkerUrl?: URL | string;\n}\n\nexport interface Destructible3DHandle {\n\tfracture(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): readonly DestructibleMesh[];\n\tprebake(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): void;\n\tprebakeAsync(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): Promise<void>;\n\trepair(): void;\n\tisFractured(): boolean;\n\tgetFragments(): readonly DestructibleMesh[];\n}\n\ninterface PrebakedFragmentTemplate {\n\tgeometry: BufferGeometry;\n\tposition: Vector3;\n\tquaternion: Quaternion;\n\tscale: Vector3;\n}\n\ninterface RuntimeState {\n\tfragmentContainer: Group | null;\n\tfragmentEntities: GameEntity<any>[];\n\tfragments: DestructibleMesh[];\n\tprebakedFragments: PrebakedFragmentTemplate[];\n\tprebakedFractureKey: string | null;\n\tcreatedRootGroup: boolean;\n\tfractureMode: 'compound' | 'independent' | null;\n\tisFractured: boolean;\n\toriginalMeshParent: Object3D | null;\n\toriginalColliderDesc: ColliderDesc | undefined;\n\toriginalColliderDescs: ColliderDesc[];\n\toriginalMeshVisible: boolean;\n\toriginalGroupVisible: boolean;\n\tsourceBodySnapshot: PhysicsSnapshot | null;\n\tsourcePhysicsAttached: boolean;\n}\n\ninterface PhysicsSnapshot {\n\ttranslation: { x: number; y: number; z: number };\n\trotation: { x: number; y: number; z: number; w: number };\n\tlinearVelocity: { x: number; y: number; z: number };\n\tangularVelocity: { x: number; y: number; z: number };\n}\n\ntype BehaviorWorld = {\n\tinterpolationAlpha?: number;\n\tdestroyEntity(entity: GameEntity<any>): void;\n\taddEntity(entity: GameEntity<any>): void;\n};\n\ntype BehaviorScene = {\n\tscene: {\n\t\tadd(object: Object3D): void;\n\t\tremove(object: Object3D): void;\n\t};\n};\n\nconst DESTRUCTIBLE_3D_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:destructible-3d',\n);\n\nconst DEFAULT_FRACTURE_OPTIONS: FractureOptionsInput = {\n\tfractureMethod: 'voronoi',\n\tfragmentCount: 12,\n\tvoronoiOptions: {\n\t\tmode: '3D',\n\t},\n\tfracturePlanes: {\n\t\tx: true,\n\t\ty: true,\n\t\tz: true,\n\t},\n\ttextureScale: new Vector2(1, 1),\n\ttextureOffset: new Vector2(0, 0),\n};\n\nconst DEFAULT_FRAGMENT_PHYSICS: Required<Destructible3DFragmentPhysicsOptions> = {\n\tmode: 'compound',\n\tinheritSourceVelocity: true,\n\toutwardVelocity: 3,\n\tangularVelocity: 1.5,\n};\n\nconst defaultOptions: Destructible3DBehaviorOptions = {\n\tfractureOptions: DEFAULT_FRACTURE_OPTIONS,\n\tinnerMaterial: null,\n\tcollider: {\n\t\tshape: 'convexHull',\n\t\tsensor: false,\n\t\tactiveCollisionTypes: ActiveCollisionTypes.DEFAULT,\n\t},\n\tfragmentPhysics: DEFAULT_FRAGMENT_PHYSICS,\n};\n\nconst runtimeStates = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tRuntimeState\n>();\n\nfunction getRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): RuntimeState {\n\tconst existing = runtimeStates.get(ref);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\tconst state: RuntimeState = {\n\t\tfragmentContainer: null,\n\t\tfragmentEntities: [],\n\t\tfragments: [],\n\t\tprebakedFragments: [],\n\t\tprebakedFractureKey: null,\n\t\tcreatedRootGroup: false,\n\t\tfractureMode: null,\n\t\tisFractured: false,\n\t\toriginalMeshParent: null,\n\t\toriginalColliderDesc: undefined,\n\t\toriginalColliderDescs: [],\n\t\toriginalMeshVisible: true,\n\t\toriginalGroupVisible: true,\n\t\tsourceBodySnapshot: null,\n\t\tsourcePhysicsAttached: false,\n\t};\n\truntimeStates.set(ref, state);\n\treturn state;\n}\n\nconst prebakeWorkerApis = new Map<\n\tstring,\n\tComlink.Remote<DestructiblePrebakeWorkerAPI>\n>();\n\n/** One in-flight worker prebake per behavior ref (dedupes duplicate bind calls). */\nconst prebakeAsyncInFlight = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tPromise<void>\n>();\n\nfunction resolvePrebakeWorkerHref(url: URL | string): string {\n\treturn typeof url === 'string' ? url : url.href;\n}\n\nfunction getPrebakeWorkerApi(\n\turl: URL | string,\n): Comlink.Remote<DestructiblePrebakeWorkerAPI> {\n\tif (typeof Worker === 'undefined') {\n\t\tthrow new Error(\n\t\t\t'Destructible3D prebakeAsync requires a Web Worker-capable environment.',\n\t\t);\n\t}\n\tconst key = resolvePrebakeWorkerHref(url);\n\tlet api = prebakeWorkerApis.get(key);\n\tif (api) {\n\t\treturn api;\n\t}\n\tconst worker = new Worker(key, { type: 'module' });\n\tapi = Comlink.wrap(worker);\n\tprebakeWorkerApis.set(key, api);\n\treturn api;\n}\n\nfunction requireEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): GameEntity<any> {\n\tconst entity = (ref as any).__entity as GameEntity<any> | undefined;\n\tif (!entity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to be registered on a stage before calling fracture() or repair().',\n\t\t);\n\t}\n\n\treturn entity;\n}\n\nfunction getBehaviorWorld(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorWorld | null {\n\treturn ((ref as any).__world ?? null) as BehaviorWorld | null;\n}\n\nfunction getBehaviorScene(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorScene | null {\n\treturn ((ref as any).__scene ?? null) as BehaviorScene | null;\n}\n\nfunction getBehaviorCreateEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): CreateEntityFn | null {\n\treturn ((ref as any).__createEntity ?? null) as CreateEntityFn | null;\n}\n\nfunction getBehaviorGlobals(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): (() => any) | null {\n\treturn ((ref as any).__getGlobals ?? null) as (() => any) | null;\n}\n\nfunction cloneFractureOptionsInput(\n\tvalue?: FractureOptionsInput | PinataFractureOptions,\n): FractureOptionsInput {\n\tif (!value) {\n\t\treturn {};\n\t}\n\n\tif (value instanceof PinataFractureOptions) {\n\t\treturn {\n\t\t\tfractureMethod: value.fractureMethod,\n\t\t\tfragmentCount: value.fragmentCount,\n\t\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t\t? {\n\t\t\t\t\tmode: value.voronoiOptions.mode,\n\t\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\t\tpoint.clone()),\n\t\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\t\timpactRadius: value.voronoiOptions.impactRadius,\n\t\t\t\t\tprojectionAxis: value.voronoiOptions.projectionAxis,\n\t\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t\t\tuseApproximation: value.voronoiOptions.useApproximation,\n\t\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\t\tvalue.voronoiOptions.approximationNeighborCount,\n\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tfracturePlanes: value.fracturePlanes\n\t\t\t\t? { ...value.fracturePlanes }\n\t\t\t\t: undefined,\n\t\t\ttextureScale: value.textureScale?.clone(),\n\t\t\ttextureOffset: value.textureOffset?.clone(),\n\t\t\tseed: value.seed,\n\t\t};\n\t}\n\n\treturn {\n\t\t...value,\n\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t? {\n\t\t\t\t...value.voronoiOptions,\n\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\tpoint.clone()),\n\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t}\n\t\t\t: undefined,\n\t\tfracturePlanes: value.fracturePlanes\n\t\t\t? { ...value.fracturePlanes }\n\t\t\t: undefined,\n\t\ttextureScale: value.textureScale?.clone(),\n\t\ttextureOffset: value.textureOffset?.clone(),\n\t};\n}\n\nfunction resolveFractureOptions(\n\tbaseValue?: FractureOptionsInput | PinataFractureOptions,\n\toverrideValue?: FractureOptionsInput | PinataFractureOptions,\n): PinataFractureOptions {\n\tconst base = cloneFractureOptionsInput(baseValue);\n\tconst override = cloneFractureOptionsInput(overrideValue);\n\n\tconst fractureMethod =\n\t\toverride.fractureMethod\n\t\t?? base.fractureMethod\n\t\t?? DEFAULT_FRACTURE_OPTIONS.fractureMethod\n\t\t?? 'voronoi';\n\n\tconst voronoiOptions = fractureMethod === 'voronoi'\n\t\t? {\n\t\t\tmode:\n\t\t\t\toverride.voronoiOptions?.mode\n\t\t\t\t?? base.voronoiOptions?.mode\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.voronoiOptions?.mode\n\t\t\t\t?? '3D',\n\t\t\tseedPoints:\n\t\t\t\toverride.voronoiOptions?.seedPoints\n\t\t\t\t?? base.voronoiOptions?.seedPoints,\n\t\t\timpactPoint:\n\t\t\t\toverride.voronoiOptions?.impactPoint\n\t\t\t\t?? base.voronoiOptions?.impactPoint,\n\t\t\timpactRadius:\n\t\t\t\toverride.voronoiOptions?.impactRadius\n\t\t\t\t?? base.voronoiOptions?.impactRadius,\n\t\t\tprojectionAxis:\n\t\t\t\toverride.voronoiOptions?.projectionAxis\n\t\t\t\t?? base.voronoiOptions?.projectionAxis,\n\t\t\tprojectionNormal:\n\t\t\t\toverride.voronoiOptions?.projectionNormal\n\t\t\t\t?? base.voronoiOptions?.projectionNormal,\n\t\t\tuseApproximation:\n\t\t\t\toverride.voronoiOptions?.useApproximation\n\t\t\t\t?? base.voronoiOptions?.useApproximation,\n\t\t\tapproximationNeighborCount:\n\t\t\t\toverride.voronoiOptions?.approximationNeighborCount\n\t\t\t\t?? base.voronoiOptions?.approximationNeighborCount,\n\t\t}\n\t\t: undefined;\n\n\treturn new PinataFractureOptions({\n\t\tfractureMethod,\n\t\tfragmentCount:\n\t\t\toverride.fragmentCount\n\t\t\t?? base.fragmentCount\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fragmentCount\n\t\t\t?? 12,\n\t\tvoronoiOptions,\n\t\tfracturePlanes: {\n\t\t\tx:\n\t\t\t\toverride.fracturePlanes?.x\n\t\t\t\t?? base.fracturePlanes?.x\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.x\n\t\t\t\t?? true,\n\t\t\ty:\n\t\t\t\toverride.fracturePlanes?.y\n\t\t\t\t?? base.fracturePlanes?.y\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.y\n\t\t\t\t?? true,\n\t\t\tz:\n\t\t\t\toverride.fracturePlanes?.z\n\t\t\t\t?? base.fracturePlanes?.z\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.z\n\t\t\t\t?? true,\n\t\t},\n\t\ttextureScale:\n\t\t\toverride.textureScale?.clone()\n\t\t\t?? base.textureScale?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureScale?.clone()\n\t\t\t?? new Vector2(1, 1),\n\t\ttextureOffset:\n\t\t\toverride.textureOffset?.clone()\n\t\t\t?? base.textureOffset?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureOffset?.clone()\n\t\t\t?? new Vector2(0, 0),\n\t\tseed: override.seed ?? base.seed,\n\t});\n}\n\nfunction resolveColliderOptions(\n\tinput?: Destructible3DColliderOptions,\n): Required<\n\tPick<Destructible3DColliderOptions, 'shape' | 'sensor' | 'activeCollisionTypes'>\n> & Omit<Destructible3DColliderOptions, 'shape' | 'sensor' | 'activeCollisionTypes'> {\n\treturn {\n\t\tshape: input?.shape ?? defaultOptions.collider?.shape ?? 'convexHull',\n\t\tsensor: input?.sensor ?? defaultOptions.collider?.sensor ?? false,\n\t\tcollisionGroups: input?.collisionGroups,\n\t\tactiveCollisionTypes:\n\t\t\tinput?.activeCollisionTypes\n\t\t\t?? defaultOptions.collider?.activeCollisionTypes\n\t\t\t?? ActiveCollisionTypes.DEFAULT,\n\t};\n}\n\nfunction resolveFragmentPhysicsOptions(\n\tinput?: Destructible3DFragmentPhysicsOptions,\n): Required<Destructible3DFragmentPhysicsOptions> {\n\treturn {\n\t\tmode: input?.mode ?? DEFAULT_FRAGMENT_PHYSICS.mode,\n\t\tinheritSourceVelocity:\n\t\t\tinput?.inheritSourceVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.inheritSourceVelocity,\n\t\toutwardVelocity:\n\t\t\tinput?.outwardVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.outwardVelocity,\n\t\tangularVelocity:\n\t\t\tinput?.angularVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.angularVelocity,\n\t};\n}\n\nfunction findFirstMesh(root: Object3D | null | undefined): Mesh | null {\n\tlet resolved: Mesh | null = null;\n\troot?.traverse((child) => {\n\t\tif (resolved) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ((child as { isMesh?: boolean }).isMesh) {\n\t\t\tresolved = child as Mesh;\n\t\t}\n\t});\n\treturn resolved;\n}\n\nfunction requireEntityMesh(entity: GameEntity<any>): Mesh {\n\tif (entity.mesh?.geometry) {\n\t\treturn entity.mesh;\n\t}\n\n\tconst mesh = findFirstMesh(entity.group);\n\tif (!mesh?.geometry) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to have a primary mesh geometry.',\n\t\t);\n\t}\n\n\tentity.mesh = mesh;\n\tif (!entity.materials?.length) {\n\t\tif (Array.isArray(mesh.material)) {\n\t\t\tentity.materials = [...mesh.material];\n\t\t} else if (mesh.material) {\n\t\t\tentity.materials = [mesh.material];\n\t\t}\n\t}\n\n\treturn mesh;\n}\n\nfunction getPrimaryMaterial(mesh: Mesh): Material {\n\tif (Array.isArray(mesh.material)) {\n\t\tconst material = mesh.material[0];\n\t\tif (material) {\n\t\t\treturn material;\n\t\t}\n\t} else if (mesh.material) {\n\t\treturn mesh.material;\n\t}\n\n\tthrow new Error(\n\t\t'Destructible3DBehavior requires the entity mesh to have a material.',\n\t);\n}\n\nfunction ensureRootGroup(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): Group {\n\tif (entity.group) {\n\t\tstate.createdRootGroup = false;\n\t\treturn entity.group;\n\t}\n\n\tconst originalMesh = requireEntityMesh(entity);\n\tconst parent = originalMesh.parent;\n\tconst root = new Group();\n\troot.name = `${entity.name ?? entity.uuid}-destructible-root`;\n\troot.position.copy(originalMesh.position);\n\troot.quaternion.copy(originalMesh.quaternion);\n\troot.scale.copy(originalMesh.scale);\n\n\toriginalMesh.position.set(0, 0, 0);\n\toriginalMesh.quaternion.identity();\n\toriginalMesh.scale.set(1, 1, 1);\n\n\tif (parent) {\n\t\tparent.remove(originalMesh);\n\t\tparent.add(root);\n\t}\n\n\troot.add(originalMesh);\n\tentity.group = root;\n\tstate.createdRootGroup = true;\n\treturn root;\n}\n\nfunction createFractureSourceMesh(\n\tmesh: Mesh,\n\troot: Group,\n\tinnerMaterial: Material | null | undefined,\n): DestructibleMesh {\n\tconst geometry = buildNormalizedFractureSourceGeometry(mesh, root);\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn new DestructibleMesh(\n\t\tgeometry,\n\t\touterMaterial,\n\t\tinnerMaterial ?? outerMaterial,\n\t);\n}\n\nfunction createPrebakedFragmentTemplates(\n\tfragments: readonly DestructibleMesh[],\n): PrebakedFragmentTemplate[] {\n\treturn fragments.map((fragment) => {\n\t\tconst geometry = fragment.geometry.clone();\n\t\tgeometry.computeBoundingBox();\n\t\tgeometry.computeBoundingSphere();\n\t\treturn {\n\t\t\tgeometry,\n\t\t\tposition: fragment.position.clone(),\n\t\t\tquaternion: fragment.quaternion.clone(),\n\t\t\tscale: fragment.scale.clone(),\n\t\t};\n\t});\n}\n\nfunction disposePrebakedFragmentTemplates(\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): void {\n\tfor (const template of templates) {\n\t\ttemplate.geometry.dispose();\n\t}\n}\n\nfunction cachePrebakedFragments(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tfragments: readonly DestructibleMesh[],\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = createPrebakedFragmentTemplates(fragments);\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction installPrebakedTemplateParts(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tparts: Array<{\n\t\tgeometry: BufferGeometry;\n\t\tposition: Vector3;\n\t\tquaternion: Quaternion;\n\t\tscale: Vector3;\n\t}>,\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\tfor (const part of parts) {\n\t\t\tpart.geometry.dispose();\n\t\t}\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = parts.map((part) => ({\n\t\tgeometry: part.geometry,\n\t\tposition: part.position.clone(),\n\t\tquaternion: part.quaternion.clone(),\n\t\tscale: part.scale.clone(),\n\t}));\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction instantiatePrebakedFragments(\n\tmesh: Mesh,\n\tinnerMaterial: Material | null | undefined,\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): readonly DestructibleMesh[] {\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn templates.map((template) => {\n\t\tconst fragment = new DestructibleMesh(\n\t\t\ttemplate.geometry.clone(),\n\t\t\touterMaterial,\n\t\t\tinnerMaterial ?? outerMaterial,\n\t\t);\n\t\tfragment.position.copy(template.position);\n\t\tfragment.quaternion.copy(template.quaternion);\n\t\tfragment.scale.copy(template.scale);\n\t\treturn fragment;\n\t});\n}\n\nfunction tagConvexHullCollider(\n\tcolliderDesc: ColliderDesc,\n\tvertices: Float32Array,\n): ColliderDesc {\n\t(colliderDesc as any).__zylemShapeData = {\n\t\tshape: 'convexHull',\n\t\tvertices: Array.from(vertices),\n\t};\n\treturn colliderDesc;\n}\n\nfunction tagTrimeshCollider(\n\tcolliderDesc: ColliderDesc,\n\tvertices: Float32Array,\n\tindices: Uint32Array,\n): ColliderDesc {\n\t(colliderDesc as any).__zylemShapeData = {\n\t\tshape: 'trimesh',\n\t\tvertices: Array.from(vertices),\n\t\tindices: Array.from(indices),\n\t};\n\treturn colliderDesc;\n}\n\nfunction getFragmentVertices(fragment: DestructibleMesh): Float32Array {\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\tthrow new Error('Fragment geometry is missing a position attribute.');\n\t}\n\n\treturn new Float32Array(position.array as ArrayLike<number>);\n}\n\nfunction getFragmentIndices(fragment: DestructibleMesh): Uint32Array {\n\tconst geometryIndex = fragment.geometry.getIndex();\n\tif (geometryIndex) {\n\t\treturn new Uint32Array(geometryIndex.array as ArrayLike<number>);\n\t}\n\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\treturn new Uint32Array();\n\t}\n\n\treturn Uint32Array.from({ length: position.count }, (_value, index) => index);\n}\n\nfunction createCuboidCollider(fragment: DestructibleMesh): ColliderDesc {\n\tconst bounds = fragment.geometry.boundingBox ?? new Box3();\n\tif (!fragment.geometry.boundingBox) {\n\t\tfragment.geometry.computeBoundingBox();\n\t}\n\tbounds.copy(fragment.geometry.boundingBox ?? bounds);\n\tconst size = bounds.getSize(new Vector3());\n\treturn ColliderDesc.cuboid(\n\t\tMath.max(size.x / 2, 0.001),\n\t\tMath.max(size.y / 2, 0.001),\n\t\tMath.max(size.z / 2, 0.001),\n\t);\n}\n\nfunction createFragmentColliderDesc(\n\tfragment: DestructibleMesh,\n\toptions: Destructible3DColliderOptions | undefined,\n\ttranslation?: Vector3 | null,\n): ColliderDesc {\n\tconst resolved = resolveColliderOptions(options);\n\tconst vertices = getFragmentVertices(fragment);\n\n\tlet colliderDesc: ColliderDesc | null = null;\n\n\tif (resolved.shape === 'convexHull') {\n\t\tcolliderDesc = ColliderDesc.convexHull(vertices);\n\t\tif (colliderDesc) {\n\t\t\tcolliderDesc = tagConvexHullCollider(colliderDesc, vertices);\n\t\t}\n\t}\n\n\tif (!colliderDesc && resolved.shape === 'trimesh') {\n\t\tconst indices = getFragmentIndices(fragment);\n\t\tcolliderDesc = tagTrimeshCollider(\n\t\t\tColliderDesc.trimesh(vertices, indices),\n\t\t\tvertices,\n\t\t\tindices,\n\t\t);\n\t}\n\n\tif (!colliderDesc) {\n\t\tcolliderDesc = createCuboidCollider(fragment);\n\t}\n\n\tif (translation) {\n\t\tcolliderDesc.setTranslation(\n\t\t\ttranslation.x,\n\t\t\ttranslation.y,\n\t\t\ttranslation.z,\n\t\t);\n\t}\n\tcolliderDesc.setSensor(resolved.sensor);\n\tif (resolved.collisionGroups !== undefined) {\n\t\tcolliderDesc.setCollisionGroups(resolved.collisionGroups);\n\t}\n\tcolliderDesc.activeCollisionTypes = resolved.activeCollisionTypes;\n\treturn colliderDesc;\n}\n\nfunction snapshotBody(entity: GameEntity<any>): PhysicsSnapshot | null {\n\tif (!entity.body) {\n\t\treturn null;\n\t}\n\n\tconst translation = entity.body.translation();\n\tconst rotation = entity.body.rotation();\n\tconst linearVelocity = entity.body.linvel();\n\tconst angularVelocity = entity.body.angvel();\n\n\treturn {\n\t\ttranslation: { ...translation },\n\t\trotation: { ...rotation },\n\t\tlinearVelocity: { ...linearVelocity },\n\t\tangularVelocity: { ...angularVelocity },\n\t};\n}\n\nfunction restoreBodySnapshot(\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tif (!snapshot || !entity.body) {\n\t\treturn;\n\t}\n\n\tentity.body.setTranslation(snapshot.translation, true);\n\tentity.body.setRotation(snapshot.rotation, true);\n\tentity.body.setLinvel(snapshot.linearVelocity, true);\n\tentity.body.setAngvel(snapshot.angularVelocity, true);\n}\n\nfunction attachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.colliderDesc) {\n\t\treturn;\n\t}\n\n\tif (entity.physicsAttached) {\n\t\tworld.destroyEntity(entity);\n\t}\n\n\tworld.addEntity(entity);\n\trestoreBodySnapshot(entity, snapshot);\n}\n\nfunction detachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.physicsAttached) {\n\t\treturn;\n\t}\n\n\tworld.destroyEntity(entity);\n}\n\nfunction disposeFragments(fragments: readonly DestructibleMesh[]): void {\n\tfor (const fragment of fragments) {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n}\n\nfunction syncRuntimeFragmentEntityTransform(\n\tentity: GameEntity<any>,\n\tinterpolationAlpha: number,\n): void {\n\tconst target = entity.group ?? entity.mesh;\n\tif (!target) {\n\t\treturn;\n\t}\n\n\tconst wasmPose = (entity as any).getPose?.();\n\tif (wasmPose && (entity as any).runtimeHandle >= 0) {\n\t\ttarget.position.set(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z);\n\t\ttarget.quaternion.set(wasmPose.rotation.x, wasmPose.rotation.y, wasmPose.rotation.z, wasmPose.rotation.w);\n\t\treturn;\n\t}\n\n\tif (!entity.body) {\n\t\treturn;\n\t}\n\tconst pose = getBodyRenderPose(entity.body as any, interpolationAlpha);\n\ttarget.position.set(pose.position.x, pose.position.y, pose.position.z);\n\ttarget.quaternion.set(pose.rotation.x, pose.rotation.y, pose.rotation.z, pose.rotation.w);\n}\n\nfunction bakeScaleIntoFragmentGeometry(\n\tfragment: DestructibleMesh,\n\tscale: Vector3,\n): void {\n\tif (\n\t\tMath.abs(scale.x - 1) < 1e-6\n\t\t&& Math.abs(scale.y - 1) < 1e-6\n\t\t&& Math.abs(scale.z - 1) < 1e-6\n\t) {\n\t\treturn;\n\t}\n\n\tfragment.geometry.applyMatrix4(\n\t\tnew Matrix4().makeScale(scale.x, scale.y, scale.z),\n\t);\n\tfragment.geometry.computeBoundingBox();\n\tfragment.geometry.computeBoundingSphere();\n}\n\nfunction getRootWorldPosition(root: Group): Vector3 {\n\troot.updateMatrixWorld(true);\n\treturn root.getWorldPosition(new Vector3());\n}\n\nfunction getImpactPointWorld(\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n): Vector3 | null {\n\tconst localImpactPoint = fractureOptions.voronoiOptions?.impactPoint;\n\tif (!localImpactPoint) {\n\t\treturn null;\n\t}\n\n\troot.updateMatrixWorld(true);\n\treturn localImpactPoint.clone().applyMatrix4(root.matrixWorld);\n}\n\nfunction computeFragmentWorldPose(\n\troot: Group,\n\tfragment: DestructibleMesh,\n): {\n\tposition: Vector3;\n\trotation: Quaternion;\n\tscale: Vector3;\n} {\n\troot.updateMatrixWorld(true);\n\tfragment.updateMatrix();\n\n\tconst worldMatrix = new Matrix4()\n\t\t.copy(root.matrixWorld)\n\t\t.multiply(fragment.matrix);\n\tconst position = new Vector3();\n\tconst rotation = new Quaternion();\n\tconst scale = new Vector3();\n\n\tworldMatrix.decompose(position, rotation, scale);\n\treturn {\n\t\tposition,\n\t\trotation,\n\t\tscale,\n\t};\n}\n\nfunction pseudoRandomSigned(index: number, salt: number): number {\n\tconst value = Math.sin((index + 1) * 12.9898 + salt * 78.233) * 43758.5453;\n\treturn (value - Math.floor(value)) * 2 - 1;\n}\n\nfunction computeFragmentAngularVelocity(\n\tindex: number,\n\tmagnitude: number,\n): { x: number; y: number; z: number } {\n\tif (magnitude <= 0) {\n\t\treturn { x: 0, y: 0, z: 0 };\n\t}\n\n\tconst axis = new Vector3(\n\t\tpseudoRandomSigned(index, 0.13),\n\t\tpseudoRandomSigned(index, 0.47),\n\t\tpseudoRandomSigned(index, 0.91),\n\t);\n\tif (axis.lengthSq() <= 1e-6) {\n\t\taxis.set(0.35, 1, 0.2);\n\t}\n\taxis.normalize().multiplyScalar(magnitude);\n\treturn {\n\t\tx: axis.x,\n\t\ty: axis.y,\n\t\tz: axis.z,\n\t};\n}\n\nfunction computeFragmentLinearVelocity(\n\tfragmentWorldPosition: Vector3,\n\trootWorldPosition: Vector3,\n\timpactPointWorld: Vector3 | null,\n\tphysicsOptions: Required<Destructible3DFragmentPhysicsOptions>,\n\tsourceVelocity: { x: number; y: number; z: number } | null,\n): { x: number; y: number; z: number } {\n\tconst velocity = new Vector3();\n\n\tif (physicsOptions.inheritSourceVelocity && sourceVelocity) {\n\t\tvelocity.set(\n\t\t\tsourceVelocity.x,\n\t\t\tsourceVelocity.y,\n\t\t\tsourceVelocity.z,\n\t\t);\n\t}\n\n\tif (physicsOptions.outwardVelocity <= 0) {\n\t\treturn {\n\t\t\tx: velocity.x,\n\t\t\ty: velocity.y,\n\t\t\tz: velocity.z,\n\t\t};\n\t}\n\n\tconst direction = fragmentWorldPosition.clone().sub(\n\t\timpactPointWorld ?? rootWorldPosition,\n\t);\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.copy(fragmentWorldPosition).sub(rootWorldPosition);\n\t}\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.set(0, 1, 0);\n\t}\n\tdirection.normalize().multiplyScalar(physicsOptions.outwardVelocity);\n\tvelocity.add(direction);\n\n\treturn {\n\t\tx: velocity.x,\n\t\ty: velocity.y,\n\t\tz: velocity.z,\n\t};\n}\n\nfunction createRuntimeFragmentEntity(\n\tcreateEntity: CreateEntityFn,\n\tparentEntity: GameEntity<any>,\n\tfragment: DestructibleMesh,\n\tindex: number,\n\tcolliderOptions: Destructible3DColliderOptions | undefined,\n\tposition: Vector3,\n\trotation: Quaternion,\n): GameEntity<any> {\n\tconst entity = createEntity({\n\t\tname: `${parentEntity.name ?? parentEntity.uuid}-fragment-${index}`,\n\t});\n\n\tentity.onCleanup(() => {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t});\n\tentity.create();\n\n\tentity.mesh = fragment;\n\tif (Array.isArray(fragment.material)) {\n\t\tentity.materials = [...fragment.material];\n\t} else if (fragment.material) {\n\t\tentity.materials = [fragment.material];\n\t}\n\n\tentity.colliderDesc = createFragmentColliderDesc(fragment, colliderOptions);\n\tentity.colliderDescs = [entity.colliderDesc];\n\tentity.bodyDesc = RigidBodyDesc.dynamic()\n\t\t.setTranslation(position.x, position.y, position.z)\n\t\t.setCanSleep(false)\n\t\t.setCcdEnabled(true);\n\n\tfragment.position.set(0, 0, 0);\n\tfragment.quaternion.identity();\n\tfragment.scale.set(1, 1, 1);\n\tentity.bodyDesc.setRotation({\n\t\tx: rotation.x,\n\t\ty: rotation.y,\n\t\tz: rotation.z,\n\t\tw: rotation.w,\n\t});\n\n\treturn entity;\n}\n\n/**\n * {@link ZylemWorld} locks translations and rotations on every new rigid body\n * when world gravity is `(0,0,0)`, so entities do not drift in zero‑G scenes.\n * Independent destructible fragments are still meant to move via\n * `setLinvel` / `setAngvel`, so they must opt out of that lock after spawn.\n */\nfunction unlockIndependentFragmentPhysicsBody(entity: GameEntity<any>): void {\n\tconst body = entity.body as\n\t\t| {\n\t\t\tlockTranslations?(locked: boolean, wakeUp?: boolean): void;\n\t\t\tlockRotations?(locked: boolean, wakeUp?: boolean): void;\n\t\t}\n\t\t| null\n\t\t| undefined;\n\tif (!body?.lockTranslations || !body.lockRotations) {\n\t\treturn;\n\t}\n\tbody.lockTranslations(false, true);\n\tbody.lockRotations(false, true);\n}\n\nfunction destroyRuntimeFragmentEntities(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tconst handledFragments = new Set<DestructibleMesh>();\n\n\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\tconst fragmentMesh = fragmentEntity.mesh as DestructibleMesh | undefined;\n\t\tif (fragmentMesh) {\n\t\t\thandledFragments.add(fragmentMesh);\n\t\t}\n\n\t\ttry {\n\t\t\tfragmentEntity.nodeDestroy({\n\t\t\t\tme: fragmentEntity,\n\t\t\t\tglobals: getBehaviorGlobals(ref)?.() ?? {},\n\t\t\t} as any);\n\t\t} catch {\n\t\t\t// Cleanup is best-effort for behavior-managed runtime fragments.\n\t\t}\n\n\t\tif (world && fragmentEntity.physicsAttached) {\n\t\t\tworld.destroyEntity(fragmentEntity);\n\t\t}\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene?.scene.remove(target);\n\t\t}\n\t}\n\n\tfor (const fragment of state.fragments) {\n\t\tif (handledFragments.has(fragment)) {\n\t\t\tcontinue;\n\t\t}\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n\n\tstate.fragmentEntities = [];\n}\n\nfunction restoreOriginalMesh(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): void {\n\tif (!entity.mesh) {\n\t\treturn;\n\t}\n\n\tif (state.createdRootGroup && entity.group) {\n\t\tconst root = entity.group;\n\t\tconst parent = root.parent;\n\t\tentity.mesh.position.copy(root.position);\n\t\tentity.mesh.quaternion.copy(root.quaternion);\n\t\tentity.mesh.scale.copy(root.scale);\n\t\tentity.mesh.removeFromParent();\n\n\t\tif (parent) {\n\t\t\tparent.remove(root);\n\t\t\tparent.add(entity.mesh);\n\t\t}\n\n\t\tentity.group = undefined;\n\t\treturn;\n\t}\n\n\tconst parent = state.originalMeshParent ?? entity.group;\n\tif (parent && entity.mesh.parent !== parent) {\n\t\tparent.add(entity.mesh);\n\t}\n}\n\nfunction restoreRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\trefreshPhysics: boolean,\n): void {\n\tconst state = getRuntimeState(ref);\n\tif (!state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst entity = requireEntity(ref);\n\n\tif (state.fractureMode === 'independent') {\n\t\tdestroyRuntimeFragmentEntities(ref, state);\n\t} else {\n\t\tstate.fragmentContainer?.removeFromParent();\n\t\tstate.fragmentContainer?.clear();\n\t\tdisposeFragments(state.fragments);\n\t}\n\n\tstate.fragmentContainer = null;\n\tstate.fragments = [];\n\n\trestoreOriginalMesh(entity, state);\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = state.originalMeshVisible;\n\t}\n\tif (entity.group) {\n\t\tentity.group.visible = state.originalGroupVisible;\n\t}\n\n\tentity.colliderDesc = state.originalColliderDesc;\n\tentity.colliderDescs = [...state.originalColliderDescs];\n\tif (!entity.colliderDesc && entity.colliderDescs.length > 0) {\n\t\tentity.colliderDesc = entity.colliderDescs[0];\n\t}\n\n\tif (refreshPhysics && state.sourcePhysicsAttached) {\n\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t}\n\n\tstate.createdRootGroup = false;\n\tstate.fractureMode = null;\n\tstate.originalMeshParent = null;\n\tstate.originalColliderDesc = undefined;\n\tstate.originalColliderDescs = [];\n\tstate.originalMeshVisible = true;\n\tstate.originalGroupVisible = true;\n\tstate.sourceBodySnapshot = null;\n\tstate.sourcePhysicsAttached = false;\n\tstate.isFractured = false;\n}\n\nfunction disposeRuntimeState(state: RuntimeState): void {\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = [];\n\tstate.prebakedFractureKey = null;\n}\n\nfunction fractureCompoundEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst fragmentContainer = new Group();\n\tfragmentContainer.name = `${entity.name ?? entity.uuid}-fracture-fragments`;\n\tfor (const fragment of fragments) {\n\t\tfragmentContainer.add(fragment);\n\t}\n\n\tentity.mesh?.removeFromParent();\n\troot.add(fragmentContainer);\n\n\tstate.fragmentContainer = fragmentContainer;\n\tstate.fractureMode = 'compound';\n\n\tconst colliderDescs = fragments.map((fragment) =>\n\t\tcreateFragmentColliderDesc(\n\t\t\tfragment,\n\t\t\tref.options.collider,\n\t\t\tfragment.position,\n\t\t));\n\tif (colliderDescs.length > 0) {\n\t\tentity.colliderDescs = colliderDescs;\n\t\tentity.colliderDesc = colliderDescs[0];\n\t\tif (state.sourcePhysicsAttached) {\n\t\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t\t}\n\t}\n}\n\nfunction fractureIndependentEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tif (!world || !scene) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require an active scene and physics world.',\n\t\t);\n\t}\n\n\tconst createEntity = getBehaviorCreateEntity(ref);\n\tif (!createEntity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require a host entity factory (BehaviorSystemContext.createEntity).',\n\t\t);\n\t}\n\n\tconst physicsOptions = resolveFragmentPhysicsOptions(ref.options.fragmentPhysics);\n\tconst rootWorldPosition = getRootWorldPosition(root);\n\tconst impactPointWorld = getImpactPointWorld(root, fractureOptions);\n\tconst sourceVelocity = state.sourceBodySnapshot?.linearVelocity ?? null;\n\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = false;\n\t}\n\tif (state.sourcePhysicsAttached) {\n\t\tdetachEntityPhysics(ref, entity);\n\t}\n\n\tconst fragmentEntities: GameEntity<any>[] = [];\n\n\tfor (const [index, fragment] of fragments.entries()) {\n\t\tconst fragmentWorldPose = computeFragmentWorldPose(root, fragment);\n\t\tbakeScaleIntoFragmentGeometry(fragment, fragmentWorldPose.scale);\n\n\t\tconst fragmentEntity = createRuntimeFragmentEntity(\n\t\t\tcreateEntity,\n\t\t\tentity,\n\t\t\tfragment,\n\t\t\tindex,\n\t\t\tref.options.collider,\n\t\t\tfragmentWorldPose.position,\n\t\t\tfragmentWorldPose.rotation,\n\t\t);\n\n\t\tworld.addEntity(fragmentEntity);\n\t\tunlockIndependentFragmentPhysicsBody(fragmentEntity);\n\t\tconst linearVelocity = computeFragmentLinearVelocity(\n\t\t\tfragmentWorldPose.position,\n\t\t\trootWorldPosition,\n\t\t\timpactPointWorld,\n\t\t\tphysicsOptions,\n\t\t\tsourceVelocity,\n\t\t);\n\t\tfragmentEntity.body?.setLinvel(linearVelocity, true);\n\t\tfragmentEntity.body?.setAngvel(\n\t\t\tcomputeFragmentAngularVelocity(\n\t\t\t\tindex,\n\t\t\t\tphysicsOptions.angularVelocity,\n\t\t\t),\n\t\t\ttrue,\n\t\t);\n\n\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\tfragmentEntity,\n\t\t\tworld.interpolationAlpha ?? 0,\n\t\t);\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene.scene.add(target);\n\t\t}\n\n\t\tfragmentEntities.push(fragmentEntity);\n\t}\n\n\tstate.fragmentEntities = fragmentEntities;\n\tstate.fractureMode = 'independent';\n}\n\nfunction fractureEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): readonly DestructibleMesh[] {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\trestoreRuntimeState(ref, true);\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\n\tconst root = ensureRootGroup(entity, state);\n\tstate.originalMeshParent = sourceMesh.parent;\n\tstate.originalColliderDesc = entity.colliderDesc;\n\tstate.originalColliderDescs = entity.colliderDescs.length > 0\n\t\t? [...entity.colliderDescs]\n\t\t: entity.colliderDesc\n\t\t\t? [entity.colliderDesc]\n\t\t\t: [];\n\tstate.originalMeshVisible = sourceMesh.visible;\n\tstate.originalGroupVisible = entity.group?.visible ?? true;\n\tstate.sourceBodySnapshot = snapshotBody(entity);\n\tstate.sourcePhysicsAttached = entity.physicsAttached;\n\n\tconst usePrebakedFragments =\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0;\n\tconst source = usePrebakedFragments\n\t\t? null\n\t\t: createFractureSourceMesh(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t\tref.options.innerMaterial,\n\t\t);\n\n\ttry {\n\t\tconst fragmentPhysics = resolveFragmentPhysicsOptions(\n\t\t\tref.options.fragmentPhysics,\n\t\t);\n\t\tconst fragments = usePrebakedFragments\n\t\t\t? instantiatePrebakedFragments(\n\t\t\t\tsourceMesh,\n\t\t\t\tref.options.innerMaterial,\n\t\t\t\tstate.prebakedFragments,\n\t\t\t)\n\t\t\t: source!.fracture(fractureOptions);\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\n\t\tstate.fragments = [...fragments];\n\t\tstate.isFractured = true;\n\n\t\tif (fragmentPhysics.mode === 'independent') {\n\t\t\tfractureIndependentEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfractureOptions,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t} else {\n\t\t\tfractureCompoundEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t}\n\n\t\treturn fragments;\n\t} catch (error) {\n\t\trestoreRuntimeState(ref, true);\n\t\tthrow error;\n\t} finally {\n\t\tsource?.geometry.dispose();\n\t}\n}\n\nfunction prebakeEntityGeometryOnly(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst root = ensureRootGroup(entity, state);\n\tconst createdRootGroup = state.createdRootGroup;\n\n\tconst source = createFractureSourceMesh(\n\t\tsourceMesh,\n\t\troot,\n\t\tref.options.innerMaterial,\n\t);\n\ttry {\n\t\tconst fragments = source.fracture(fractureOptions) as DestructibleMesh[];\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\t\tfor (const fragment of fragments) {\n\t\t\tfragment.geometry.dispose();\n\t\t}\n\t} finally {\n\t\tsource.geometry.dispose();\n\t}\n\n\tif (createdRootGroup) {\n\t\trestoreOriginalMesh(entity, state);\n\t\tstate.createdRootGroup = false;\n\t}\n}\n\nasync function prebakeEntityAsync(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): Promise<void> {\n\tconst workerUrl = ref.options.prebakeWorkerUrl;\n\tif (!workerUrl) {\n\t\tprebakeEntityGeometryOnly(ref, overrideOptions);\n\t\treturn;\n\t}\n\n\tconst existing = prebakeAsyncInFlight.get(ref);\n\tif (existing) {\n\t\tawait existing;\n\t\treturn;\n\t}\n\n\tconst job = (async () => {\n\t\tconst entity = requireEntity(ref);\n\t\tif (entity.isInstanced) {\n\t\t\tthrow new Error(\n\t\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t\t);\n\t\t}\n\n\t\tconst state = getRuntimeState(ref);\n\t\tif (state.isFractured) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fractureOptions = resolveFractureOptions(\n\t\t\tref.options.fractureOptions,\n\t\t\toverrideOptions,\n\t\t);\n\t\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\t\tif (\n\t\t\tstate.prebakedFractureKey === cacheKey\n\t\t\t&& state.prebakedFragments.length > 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sourceMesh = requireEntityMesh(entity);\n\t\tconst root = ensureRootGroup(entity, state);\n\t\tconst createdRootGroup = state.createdRootGroup;\n\n\t\tconst normalizedGeometry = buildNormalizedFractureSourceGeometry(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t);\n\n\t\tif (createdRootGroup) {\n\t\t\trestoreOriginalMesh(entity, state);\n\t\t\tstate.createdRootGroup = false;\n\t\t}\n\n\t\tconst { payload, transferables } = bufferGeometryToPlain(normalizedGeometry);\n\t\tnormalizedGeometry.dispose();\n\n\t\tconst plainOptions = pinataFractureOptionsToPlain(fractureOptions);\n\t\tconst api = getPrebakeWorkerApi(workerUrl);\n\t\tconst request = Comlink.transfer(\n\t\t\t{ geometry: payload, options: plainOptions },\n\t\t\ttransferables,\n\t\t);\n\n\t\tconst response = await api.prebake(request);\n\t\tconst parts = plainWorkerResultToTemplateParts(response);\n\t\tinstallPrebakedTemplateParts(state, cacheKey, parts);\n\t})();\n\n\tprebakeAsyncInFlight.set(ref, job);\n\ttry {\n\t\tawait job;\n\t} finally {\n\t\tif (prebakeAsyncInFlight.get(ref) === job) {\n\t\t\tprebakeAsyncInFlight.delete(ref);\n\t\t}\n\t}\n}\n\nfunction prebakeEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tprebakeEntityGeometryOnly(ref, overrideOptions);\n}\n\nfunction createDestructible3DHandle(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): Destructible3DHandle {\n\treturn {\n\t\tfracture: (overrideOptions) => fractureEntity(ref, overrideOptions),\n\t\tprebake: (overrideOptions) => {\n\t\t\tprebakeEntity(ref, overrideOptions);\n\t\t},\n\t\tprebakeAsync: (overrideOptions) => prebakeEntityAsync(ref, overrideOptions),\n\t\trepair: () => restoreRuntimeState(ref, true),\n\t\tisFractured: () => getRuntimeState(ref).isFractured,\n\t\tgetFragments: () => getRuntimeState(ref).fragments,\n\t};\n}\n\nclass Destructible3DSystem implements BehaviorSystem {\n\tconstructor(\n\t\tprivate world: unknown,\n\t\tprivate scene: unknown,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t\tprivate createEntity?: CreateEntityFn,\n\t\tprivate getGlobals?: () => any,\n\t) {\n\t\tthis.primeLinks();\n\t}\n\n\tattach(link: BehaviorEntityLink): void {\n\t\tif (link.ref?.descriptor?.key !== DESTRUCTIBLE_3D_BEHAVIOR_KEY) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.primeLink(link);\n\t}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tthis.primeLinks();\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst interpolationAlpha =\n\t\t\t(this.world as { interpolationAlpha?: number } | null)?.interpolationAlpha\n\t\t\t?? 0;\n\t\tfor (const link of links) {\n\t\t\tconst state = getRuntimeState(\n\t\t\t\tlink.ref as BehaviorRef<Destructible3DBehaviorOptions>,\n\t\t\t);\n\t\t\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\t\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\t\t\tfragmentEntity,\n\t\t\t\t\tinterpolationAlpha,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions>;\n\t\t\trestoreRuntimeState(ref, false);\n\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t}\n\t}\n\n\tprivate primeLinks(): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tthis.primeLink(link);\n\t\t}\n\t}\n\n\tprivate primeLink(link: BehaviorEntityLink): void {\n\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions> & {\n\t\t\t__cleanupRegistered?: boolean;\n\t\t};\n\t\tconst entity = link.entity as GameEntity<any>;\n\t\t(ref as any).__entity = entity;\n\t\t(ref as any).__world = this.world;\n\t\t(ref as any).__scene = this.scene;\n\t\t(ref as any).__createEntity = this.createEntity;\n\t\t(ref as any).__getGlobals = this.getGlobals;\n\n\t\tif (!ref.__cleanupRegistered) {\n\t\t\tentity.onCleanup(() => {\n\t\t\t\trestoreRuntimeState(ref, false);\n\t\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t\t});\n\t\t\tref.__cleanupRegistered = true;\n\t\t}\n\t}\n}\n\nexport const Destructible3DBehavior = defineBehavior<\n\tDestructible3DBehaviorOptions,\n\tDestructible3DHandle\n>({\n\tname: 'destructible-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Destructible3DSystem(\n\t\t\tctx.world,\n\t\t\tctx.scene,\n\t\t\tctx.getBehaviorLinks,\n\t\t\tctx.createEntity,\n\t\t\tctx.getGlobals,\n\t\t),\n\tcreateHandle: createDestructible3DHandle,\n});\n","import { Quaternion } from 'three';\n\nexport interface PhysicsVector3 {\n\tx: number;\n\ty: number;\n\tz: number;\n}\n\nexport interface PhysicsQuaternion {\n\tx: number;\n\ty: number;\n\tz: number;\n\tw: number;\n}\n\nexport interface PhysicsPose {\n\tposition: PhysicsVector3;\n\trotation: PhysicsQuaternion;\n}\n\nexport interface PhysicsPoseHistory {\n\tprevious: PhysicsPose;\n\tcurrent: PhysicsPose;\n}\n\nexport interface PhysicsPoseReadable {\n\ttranslation(): PhysicsVector3;\n\trotation(): PhysicsQuaternion;\n}\n\nexport interface PhysicsRenderPoseProvider {\n\tgetPoseHistory(): PhysicsPoseHistory;\n\tgetRenderPose(alpha: number): PhysicsPose;\n}\n\nconst directBodyPoseHistory = new WeakMap<object, PhysicsPoseHistory>();\nconst _previousQuaternion = new Quaternion();\nconst _currentQuaternion = new Quaternion();\nconst _renderQuaternion = new Quaternion();\n\nexport function createPhysicsPose(\n\tposition: Partial<PhysicsVector3> = {},\n\trotation: Partial<PhysicsQuaternion> = {},\n): PhysicsPose {\n\treturn {\n\t\tposition: {\n\t\t\tx: position.x ?? 0,\n\t\t\ty: position.y ?? 0,\n\t\t\tz: position.z ?? 0,\n\t\t},\n\t\trotation: {\n\t\t\tx: rotation.x ?? 0,\n\t\t\ty: rotation.y ?? 0,\n\t\t\tz: rotation.z ?? 0,\n\t\t\tw: rotation.w ?? 1,\n\t\t},\n\t};\n}\n\nexport function clonePhysicsVector3(vector: PhysicsVector3): PhysicsVector3 {\n\treturn { x: vector.x, y: vector.y, z: vector.z };\n}\n\nexport function clonePhysicsQuaternion(\n\trotation: PhysicsQuaternion,\n): PhysicsQuaternion {\n\treturn { x: rotation.x, y: rotation.y, z: rotation.z, w: rotation.w };\n}\n\nexport function clonePhysicsPose(pose: PhysicsPose): PhysicsPose {\n\treturn {\n\t\tposition: clonePhysicsVector3(pose.position),\n\t\trotation: clonePhysicsQuaternion(pose.rotation),\n\t};\n}\n\nexport function clampInterpolationAlpha(alpha: number): number {\n\tif (!Number.isFinite(alpha)) return 0;\n\treturn Math.max(0, Math.min(1, alpha));\n}\n\nexport function capturePhysicsPose(body: PhysicsPoseReadable): PhysicsPose {\n\treturn {\n\t\tposition: clonePhysicsVector3(body.translation()),\n\t\trotation: clonePhysicsQuaternion(body.rotation()),\n\t};\n}\n\nexport function createCollapsedPhysicsPoseHistory(\n\tpose: PhysicsPose,\n): PhysicsPoseHistory {\n\tconst current = clonePhysicsPose(pose);\n\treturn {\n\t\tprevious: clonePhysicsPose(current),\n\t\tcurrent,\n\t};\n}\n\nexport function registerDirectBodyPoseHistory(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\tconst history = createCollapsedPhysicsPoseHistory(capturePhysicsPose(body));\n\tdirectBodyPoseHistory.set(body, history);\n\treturn history;\n}\n\nexport function getDirectBodyPoseHistory(\n\tbody: object,\n): PhysicsPoseHistory | null {\n\treturn directBodyPoseHistory.get(body) ?? null;\n}\n\nexport function collapseDirectBodyPoseHistory(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\tconst pose = capturePhysicsPose(body);\n\tconst history =\n\t\tdirectBodyPoseHistory.get(body) ?? createCollapsedPhysicsPoseHistory(pose);\n\n\thistory.previous = clonePhysicsPose(pose);\n\thistory.current = clonePhysicsPose(pose);\n\tdirectBodyPoseHistory.set(body, history);\n\n\treturn history;\n}\n\nexport function prepareDirectBodyPoseHistoryStep(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\treturn collapseDirectBodyPoseHistory(body);\n}\n\nexport function commitDirectBodyPoseHistoryStep(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\tconst pose = capturePhysicsPose(body);\n\tconst history =\n\t\tdirectBodyPoseHistory.get(body) ?? createCollapsedPhysicsPoseHistory(pose);\n\n\thistory.current = clonePhysicsPose(pose);\n\tdirectBodyPoseHistory.set(body, history);\n\n\treturn history;\n}\n\nexport function interpolatePhysicsPose(\n\tprevious: PhysicsPose,\n\tcurrent: PhysicsPose,\n\talpha: number,\n): PhysicsPose {\n\tconst t = clampInterpolationAlpha(alpha);\n\n\t_previousQuaternion.set(\n\t\tprevious.rotation.x,\n\t\tprevious.rotation.y,\n\t\tprevious.rotation.z,\n\t\tprevious.rotation.w,\n\t);\n\t_currentQuaternion.set(\n\t\tcurrent.rotation.x,\n\t\tcurrent.rotation.y,\n\t\tcurrent.rotation.z,\n\t\tcurrent.rotation.w,\n\t);\n\t_renderQuaternion.slerpQuaternions(\n\t\t_previousQuaternion,\n\t\t_currentQuaternion,\n\t\tt,\n\t);\n\n\treturn {\n\t\tposition: {\n\t\t\tx: previous.position.x + (current.position.x - previous.position.x) * t,\n\t\t\ty: previous.position.y + (current.position.y - previous.position.y) * t,\n\t\t\tz: previous.position.z + (current.position.z - previous.position.z) * t,\n\t\t},\n\t\trotation: {\n\t\t\tx: _renderQuaternion.x,\n\t\t\ty: _renderQuaternion.y,\n\t\t\tz: _renderQuaternion.z,\n\t\t\tw: _renderQuaternion.w,\n\t\t},\n\t};\n}\n\nexport function getBodyPoseHistory(body: unknown): PhysicsPoseHistory | null {\n\tif (isRenderPoseProvider(body)) {\n\t\treturn body.getPoseHistory();\n\t}\n\tif (isPhysicsPoseReadable(body)) {\n\t\treturn directBodyPoseHistory.get(body as object) ?? null;\n\t}\n\treturn null;\n}\n\nexport function getBodyRenderPose(\n\tbody: PhysicsPoseReadable | PhysicsRenderPoseProvider,\n\talpha: number,\n): PhysicsPose {\n\tif (isRenderPoseProvider(body)) {\n\t\treturn body.getRenderPose(alpha);\n\t}\n\n\tconst history = directBodyPoseHistory.get(body as object);\n\tif (!history) {\n\t\treturn capturePhysicsPose(body);\n\t}\n\n\tconst latestPose = capturePhysicsPose(body);\n\tif (!posesEqual(latestPose, history.current)) {\n\t\tconst collapsed = collapseDirectBodyPoseHistory(body as object & PhysicsPoseReadable);\n\t\treturn clonePhysicsPose(collapsed.current);\n\t}\n\n\treturn interpolatePhysicsPose(history.previous, history.current, alpha);\n}\n\nfunction isPhysicsPoseReadable(value: unknown): value is PhysicsPoseReadable {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof (value as PhysicsPoseReadable).translation === 'function' &&\n\t\ttypeof (value as PhysicsPoseReadable).rotation === 'function'\n\t);\n}\n\nfunction isRenderPoseProvider(value: unknown): value is PhysicsRenderPoseProvider {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof (value as PhysicsRenderPoseProvider).getPoseHistory === 'function' &&\n\t\ttypeof (value as PhysicsRenderPoseProvider).getRenderPose === 'function'\n\t);\n}\n\nfunction posesEqual(a: PhysicsPose, b: PhysicsPose): boolean {\n\treturn (\n\t\ta.position.x === b.position.x &&\n\t\ta.position.y === b.position.y &&\n\t\ta.position.z === b.position.z &&\n\t\ta.rotation.x === b.rotation.x &&\n\t\ta.rotation.y === b.rotation.y &&\n\t\ta.rotation.z === b.rotation.z &&\n\t\ta.rotation.w === b.rotation.w\n\t);\n}\n","export * from './destructible-3d.descriptor';\nexport type {\n\tDestructiblePrebakeWorkerAPI,\n\tPlainBufferGeometryPayload,\n\tPlainFractureOptions,\n\tPrebakeWorkerRequest,\n\tPrebakeWorkerResponse,\n} from '../../destructible-prebake';\nexport {\n\tDestructibleMesh,\n\tFractureOptions,\n\ttype VoronoiOptions,\n} from '@dgreenheck/three-pinata';\n"],"mappings":"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","names":["Quaternion","Quaternion","parent","DestructibleMesh"]}
@@ -24,3 +24,4 @@ export {
24
24
  createTopDownMovementInputComponent,
25
25
  createTopDownMovementStateComponent
26
26
  };
27
+ //# sourceMappingURL=chunk-EIWQM6U3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/top-down-movement/components.ts"],"sourcesContent":["export interface TopDownMovementComponent {\n\tmoveSpeed: number;\n}\n\nexport function createTopDownMovementComponent(\n\toptions: Partial<TopDownMovementComponent> = {},\n): TopDownMovementComponent {\n\treturn {\n\t\tmoveSpeed: options.moveSpeed ?? 8,\n\t};\n}\n\nexport interface TopDownMovementInputComponent {\n\tmoveX: number;\n\tmoveY: number;\n\tfaceX: number;\n\tfaceY: number;\n}\n\nexport function createTopDownMovementInputComponent(): TopDownMovementInputComponent {\n\treturn {\n\t\tmoveX: 0,\n\t\tmoveY: 0,\n\t\tfaceX: 0,\n\t\tfaceY: 0,\n\t};\n}\n\nexport interface TopDownMovementStateComponent {\n\tfacingAngle: number;\n\tmoving: boolean;\n}\n\nexport function createTopDownMovementStateComponent(): TopDownMovementStateComponent {\n\treturn {\n\t\tfacingAngle: 0,\n\t\tmoving: false,\n\t};\n}\n"],"mappings":";AAIO,SAAS,+BACf,UAA6C,CAAC,GACnB;AAC3B,SAAO;AAAA,IACN,WAAW,QAAQ,aAAa;AAAA,EACjC;AACD;AASO,SAAS,sCAAqE;AACpF,SAAO;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACR;AACD;AAOO,SAAS,sCAAqE;AACpF,SAAO;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,EACT;AACD;","names":[]}
@@ -11,3 +11,4 @@ function defineBehavior(config) {
11
11
  export {
12
12
  defineBehavior
13
13
  };
14
+ //# sourceMappingURL=chunk-EZNCCO4L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/behavior-descriptor.ts"],"sourcesContent":["/**\n * BehaviorDescriptor\n *\n * Type-safe behavior descriptors that provide options inference.\n * Used with entity.use() to declaratively attach behaviors to entities.\n *\n * Each behavior can define its own handle type via `createHandle`,\n * providing behavior-specific methods with full type safety.\n */\n\nimport type { BehaviorSystemFactory } from './behavior-system';\n\n/**\n * Base handle returned by entity.use() for lazy access to behavior runtime.\n * FSM is null until entity is spawned and components are initialized.\n */\nexport interface BaseBehaviorHandle<\n O extends Record<string, any> = Record<string, any>,\n> {\n /** Get the FSM instance (null until entity is spawned) */\n getFSM(): any | null;\n /** Get the current options */\n getOptions(): O;\n /** Access the underlying behavior ref */\n readonly ref: BehaviorRef<O>;\n}\n\n/**\n * Reference to a behavior stored on an entity\n */\nexport interface BehaviorRef<\n O extends Record<string, any> = Record<string, any>,\n> {\n /** The behavior descriptor */\n descriptor: BehaviorDescriptor<O, any>;\n /** Merged options (defaults + overrides) */\n options: O;\n /** Optional FSM instance - set lazily when entity is spawned */\n fsm?: any;\n}\n\n/**\n * A typed behavior descriptor that associates a symbol key with:\n * - Default options (providing type inference)\n * - A system factory to create the behavior system\n * - An optional handle factory for behavior-specific methods\n */\nexport interface BehaviorDescriptor<\n O extends Record<string, any> = Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n I = unknown,\n> {\n /** Unique symbol identifying this behavior */\n readonly key: symbol;\n /** Default options (used for type inference) */\n readonly defaultOptions: O;\n /** Factory to create the behavior system */\n readonly systemFactory: any;\n /**\n * Optional factory to create behavior-specific handle methods.\n * These methods are merged into the handle returned by entity.use().\n */\n readonly createHandle?: (ref: any) => H;\n}\n\n/**\n * The full handle type returned by entity.use().\n * Combines base handle with behavior-specific methods.\n */\nexport type BehaviorHandle<\n O extends Record<string, any> = Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n> = BaseBehaviorHandle<O> & H;\n\n/**\n * Configuration for defining a new behavior\n */\nexport interface DefineBehaviorConfig<\n O extends Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n I = unknown,\n> {\n /** Human-readable name for debugging */\n name: string;\n /** Default options - these define the type */\n defaultOptions: O;\n /** Factory function to create the system */\n systemFactory: BehaviorSystemFactory;\n /**\n * Optional factory to create behavior-specific handle methods.\n * The returned object is merged into the handle returned by entity.use().\n *\n * @example\n * ```typescript\n * createHandle: (ref) => ({\n * getLastHits: () => ref.fsm?.getLastHits() ?? null,\n * getMovement: (moveX, moveY) => ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },\n * }),\n * ```\n */\n createHandle?: (ref: BehaviorRef<O>) => H;\n}\n\n/**\n * Define a typed behavior descriptor.\n *\n * @example\n * ```typescript\n * export const WorldBoundary2DBehavior = defineBehavior({\n * name: 'world-boundary-2d',\n * defaultOptions: { boundaries: { top: 0, bottom: 0, left: 0, right: 0 } },\n * systemFactory: (ctx) => new WorldBoundary2DSystem(ctx.world),\n * createHandle: (ref) => ({\n * getLastHits: () => ref.fsm?.getLastHits() ?? null,\n * getMovement: (moveX: number, moveY: number) =>\n * ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },\n * }),\n * });\n *\n * // Usage - handle has getLastHits and getMovement with full types\n * const boundary = ship.use(WorldBoundary2DBehavior, { ... });\n * const hits = boundary.getLastHits(); // Fully typed!\n * ```\n */\nexport function defineBehavior<\n O extends Record<string, any>,\n H extends Record<string, any> = Record<string, never>,\n I = unknown,\n>(\n config: DefineBehaviorConfig<O, H, I>,\n): BehaviorDescriptor<O, H, I> {\n return {\n key: Symbol.for(`zylem:behavior:${config.name}`),\n defaultOptions: config.defaultOptions,\n systemFactory: config.systemFactory,\n createHandle: config.createHandle,\n };\n}\n"],"mappings":";AA4HO,SAAS,eAKd,QAC6B;AAC7B,SAAO;AAAA,IACL,KAAK,uBAAO,IAAI,kBAAkB,OAAO,IAAI,EAAE;AAAA,IAC/C,gBAAgB,OAAO;AAAA,IACvB,eAAe,OAAO;AAAA,IACtB,cAAc,OAAO;AAAA,EACvB;AACF;","names":[]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  SyncStateMachine,
3
3
  t
4
- } from "./chunk-RER2IDPW.js";
4
+ } from "./chunk-4URF65BR.js";
5
5
  import {
6
6
  defineBehavior
7
- } from "./chunk-YDLO5M7S.js";
7
+ } from "./chunk-EZNCCO4L.js";
8
8
 
9
9
  // src/lib/behaviors/platformer-3d/components.ts
10
10
  function createPlatformer3DMovementComponent(options = {}) {
@@ -14,13 +14,16 @@ function createPlatformer3DMovementComponent(options = {}) {
14
14
  jumpForce: options.jumpForce ?? 12,
15
15
  maxJumps: options.maxJumps ?? 1,
16
16
  gravity: options.gravity ?? 9.82,
17
- groundRayLength: options.groundRayLength ?? 1,
18
17
  coyoteTime: options.coyoteTime ?? 0.1,
19
18
  jumpBufferTime: options.jumpBufferTime ?? 0.1,
20
19
  jumpCutMultiplier: options.jumpCutMultiplier ?? 0.5,
21
20
  multiJumpWindowTime: options.multiJumpWindowTime ?? 0.15,
22
21
  // 150ms default
23
- debugGroundProbe: options.debugGroundProbe ?? false
22
+ slopeClimbAngle: options.slopeClimbAngle ?? 50,
23
+ slopeSlideAngle: options.slopeSlideAngle ?? 40,
24
+ autostep: options.autostep ?? { maxHeight: 0.3, minWidth: 0.1 },
25
+ snapToGroundDistance: options.snapToGroundDistance ?? 0.3,
26
+ characterOffset: options.characterOffset ?? 0.05
24
27
  };
25
28
  }
26
29
  function createPlatformer3DInputComponent() {
@@ -52,7 +55,7 @@ function createPlatformer3DStateComponent() {
52
55
  timeSinceJump: 0,
53
56
  jumpedThisFrame: false,
54
57
  jumpCutRampTimer: 0,
55
- groundedGraceTimer: 0
58
+ verticalVelocity: 0
56
59
  };
57
60
  }
58
61
 
@@ -183,92 +186,52 @@ var Platformer3DFSM = class {
183
186
  }
184
187
  };
185
188
 
186
- // src/lib/behaviors/platformer-3d/platformer-3d.behavior.ts
189
+ // src/lib/behaviors/platformer-3d/platformer-3d.system.ts
190
+ import { RigidBodyType, QueryFilterFlags } from "@dimforge/rapier3d-compat";
187
191
  var JUMP_CUT_RAMP_DURATION = 0.05;
188
- var GROUNDED_GRACE_WINDOW = 0.06;
189
- var Platformer3DBehavior = class {
192
+ var GROUND_STICK_SPEED = 2;
193
+ var FALL_VELOCITY_THRESHOLD = -0.1;
194
+ var DEG_TO_RAD = Math.PI / 180;
195
+ var _desired = { x: 0, y: 0, z: 0 };
196
+ var Platformer3DSystem = class {
190
197
  world;
191
- scene;
192
- /**
193
- * Tracks entities whose Rapier `gravityScale` has been zeroed so that
194
- * `applyGravity` is the sole writer of vertical velocity. We do this
195
- * lazily on the first update because the body isn't always available at
196
- * construction time.
197
- */
198
- gravityConfiguredUUIDs = /* @__PURE__ */ new Set();
199
- constructor(world, scene) {
198
+ /** Per-entity character controllers, keyed by entity uuid. */
199
+ controllers = /* @__PURE__ */ new Map();
200
+ constructor(world) {
200
201
  this.world = world;
201
- this.scene = scene;
202
- }
203
- /**
204
- * Detect "grounded" using the actual capsule collider's contact pairs.
205
- *
206
- * A contact is treated as ground when its solver point lies below the
207
- * body center (i.e., it sits on the bottom hemisphere/cylinder). We
208
- * deliberately don't filter by normal direction: the contact point's
209
- * position alone is robust against the various normal-flip conventions
210
- * Rapier uses for `flipped` manifolds and against rolling-bottom edges
211
- * on heightmap terrain.
212
- */
213
- detectGroundedFromContacts(entity) {
214
- const collider = entity.collider;
215
- const physicsWorld = this.world?.world;
216
- if (!collider || !physicsWorld?.contactsWith) {
217
- return false;
218
- }
219
- let grounded = false;
220
- physicsWorld.contactsWith(collider, (other) => {
221
- if (grounded) return;
222
- physicsWorld.contactPair(collider, other, (manifold, flipped) => {
223
- if (grounded) return;
224
- const num = manifold.numContacts();
225
- for (let i = 0; i < num; i++) {
226
- const local = flipped ? manifold.localContactPoint2(i) : manifold.localContactPoint1(i);
227
- if (!local) continue;
228
- if (local.y < 0) {
229
- grounded = true;
230
- return;
231
- }
232
- }
233
- });
234
- });
235
- return grounded;
236
202
  }
237
203
  /**
238
- * One-time per-entity physics setup: take over gravity from Rapier's
239
- * world so that `applyGravity` controls the entire airborne fall curve.
240
- * Without this, gravity was effectively doubled (Rapier's world gravity
241
- * + this behavior's explicit gravity were both pulling the body down).
204
+ * One-time per-entity physics setup: convert the body to a
205
+ * position-based kinematic body and create its character controller.
206
+ * Done lazily on the first update because the body isn't always
207
+ * available at construction time.
242
208
  */
243
209
  ensurePhysicsConfigured(entity) {
244
- if (this.gravityConfiguredUUIDs.has(entity.uuid)) return;
245
- if (typeof entity.body?.setGravityScale === "function") {
246
- entity.body.setGravityScale(0, true);
210
+ const existing = this.controllers.get(entity.uuid);
211
+ if (existing) return existing;
212
+ const physicsWorld = this.world?.world;
213
+ if (!physicsWorld || !entity.body) return null;
214
+ if (entity.body.bodyType() !== RigidBodyType.KinematicPositionBased) {
215
+ entity.body.setBodyType(RigidBodyType.KinematicPositionBased, true);
247
216
  }
248
- this.gravityConfiguredUUIDs.add(entity.uuid);
249
- }
250
- /**
251
- * Apply horizontal movement based on input.
252
- *
253
- * Only writes X/Z axes — Y is left untouched so Rapier's contact resolution
254
- * can damp vertical motion correctly while grounded. Jump and gravity are
255
- * the sole writers of Y velocity (see handleJump / applyGravity).
256
- */
257
- applyMovement(entity) {
258
- const input = entity.$platformer;
259
217
  const movement = entity.platformer;
260
- const state = entity.platformerState;
261
- const speed = input.run ? movement.runSpeed : movement.walkSpeed;
262
- state.currentSpeed = speed;
263
- const moveX = input.moveX * speed;
264
- const moveZ = input.moveZ * speed;
265
- entity.transformStore.velocity.x = moveX;
266
- entity.transformStore.velocity.z = moveZ;
267
- entity.transformStore.dirty.velocityX = true;
268
- entity.transformStore.dirty.velocityZ = true;
218
+ const controller = physicsWorld.createCharacterController(movement.characterOffset);
219
+ controller.setUp({ x: 0, y: 1, z: 0 });
220
+ controller.setMaxSlopeClimbAngle(movement.slopeClimbAngle * DEG_TO_RAD);
221
+ controller.setMinSlopeSlideAngle(movement.slopeSlideAngle * DEG_TO_RAD);
222
+ if (movement.autostep) {
223
+ controller.enableAutostep(movement.autostep.maxHeight, movement.autostep.minWidth, true);
224
+ } else {
225
+ controller.disableAutostep();
226
+ }
227
+ controller.enableSnapToGround(movement.snapToGroundDistance);
228
+ controller.setApplyImpulsesToDynamicBodies(true);
229
+ this.controllers.set(entity.uuid, controller);
230
+ return controller;
269
231
  }
270
232
  /**
271
- * Handle jump logic with multi-jump, coyote time, buffering, and jump-cut ramp.
233
+ * Handle jump logic with multi-jump, coyote time, buffering, and jump-cut
234
+ * ramp. All vertical motion is written to `state.verticalVelocity`.
272
235
  */
273
236
  handleJump(entity, delta) {
274
237
  const input = entity.$platformer;
@@ -299,12 +262,10 @@ var Platformer3DBehavior = class {
299
262
  state.jumpCutRampTimer = JUMP_CUT_RAMP_DURATION;
300
263
  }
301
264
  if (state.jumpCutRampTimer > 0) {
302
- const velocity = entity.body.linvel();
303
- if (velocity.y > 0) {
265
+ if (state.verticalVelocity > 0) {
304
266
  const stepT = Math.min(delta / state.jumpCutRampTimer, 1);
305
- const targetY = velocity.y * movement.jumpCutMultiplier;
306
- entity.transformStore.velocity.y = velocity.y + (targetY - velocity.y) * stepT;
307
- entity.transformStore.dirty.velocityY = true;
267
+ const targetY = state.verticalVelocity * movement.jumpCutMultiplier;
268
+ state.verticalVelocity += (targetY - state.verticalVelocity) * stepT;
308
269
  }
309
270
  state.jumpCutRampTimer = Math.max(0, state.jumpCutRampTimer - delta);
310
271
  }
@@ -325,19 +286,17 @@ var Platformer3DBehavior = class {
325
286
  state.falling = false;
326
287
  state.jumpCutApplied = false;
327
288
  state.jumpCutRampTimer = 0;
328
- state.groundedGraceTimer = 0;
329
- entity.transformStore.velocity.y = movement.jumpForce;
330
- entity.transformStore.dirty.velocityY = true;
289
+ state.verticalVelocity = movement.jumpForce;
331
290
  state.jumpedThisFrame = true;
332
291
  }
333
292
  }
334
293
  /**
335
- * Apply gravity when not grounded.
294
+ * Integrate gravity into `state.verticalVelocity`.
336
295
  *
337
- * Skipped on the single frame immediately after a jump impulse is applied
338
- * (tracked via `state.jumpedThisFrame`) so gravity never overwrites a
339
- * just-applied jump velocity. The flag is cleared here regardless, so it
340
- * only suppresses exactly one gravity step — independent of frame rate.
296
+ * While grounded (and not on the jump frame) vertical velocity is held at
297
+ * a small constant downward speed so the controller stays pressed into
298
+ * the ground. Skipped entirely on the frame a jump was applied — the
299
+ * grounded flag is still stale-true then and would clobber the jump.
341
300
  */
342
301
  applyGravity(entity, delta) {
343
302
  const movement = entity.platformer;
@@ -346,58 +305,27 @@ var Platformer3DBehavior = class {
346
305
  state.jumpedThisFrame = false;
347
306
  return;
348
307
  }
349
- if (state.grounded) return;
350
- const currentVel = entity.body.linvel();
351
- const newYVelocity = currentVel.y - movement.gravity * delta;
352
- entity.transformStore.velocity.y = newYVelocity;
353
- entity.transformStore.dirty.velocityY = true;
308
+ if (state.grounded) {
309
+ state.verticalVelocity = -GROUND_STICK_SPEED;
310
+ return;
311
+ }
312
+ state.verticalVelocity -= movement.gravity * delta;
354
313
  }
355
314
  /**
356
- * Update entity state based on physics.
357
- *
358
- * Grounded is determined purely by Rapier's contact pairs on the entity's
359
- * collider. This removes a whole class of slope/heightmap jitter caused
360
- * by the previous shape probe disagreeing with the contact resolver — the
361
- * probe could report grounded while a contact impulse had just nudged the
362
- * body off the ground, producing visible micro-bouncing.
363
- *
364
- * While grounded, vertical velocity is held at 0 each frame. This stops
365
- * residual upward kicks from slope-contact resolution from accumulating
366
- * across frames (which previously caused the character to "ride up"
367
- * slopes and lose contact briefly, then fall back, then re-contact, in a
368
- * tight oscillation).
315
+ * Update entity state from the controller's grounded result.
369
316
  */
370
- updateState(entity, delta) {
317
+ updateState(entity, delta, computedGrounded) {
371
318
  const state = entity.platformerState;
372
319
  const wasGrounded = state.grounded;
373
- const velocity = entity.body.linvel();
374
- const hasContact = this.detectGroundedFromContacts(entity);
375
320
  const isAirborne = state.jumping || state.falling;
376
321
  let isGrounded;
377
322
  if (isAirborne) {
378
323
  const canLand = state.falling && !state.jumping;
379
- isGrounded = hasContact && canLand;
324
+ isGrounded = computedGrounded && canLand;
380
325
  } else {
381
- isGrounded = hasContact;
382
- }
383
- if (!isGrounded && wasGrounded) {
384
- if (state.groundedGraceTimer <= 0) {
385
- state.groundedGraceTimer = GROUNDED_GRACE_WINDOW;
386
- }
387
- }
388
- if (state.groundedGraceTimer > 0) {
389
- if (!isGrounded && wasGrounded && !isAirborne) {
390
- isGrounded = true;
391
- state.groundedGraceTimer = Math.max(0, state.groundedGraceTimer - delta);
392
- } else {
393
- state.groundedGraceTimer = 0;
394
- }
326
+ isGrounded = computedGrounded;
395
327
  }
396
328
  state.grounded = isGrounded;
397
- if (state.grounded) {
398
- entity.transformStore.velocity.y = 0;
399
- entity.transformStore.dirty.velocityY = true;
400
- }
401
329
  if (state.grounded) {
402
330
  state.timeSinceGrounded = 0;
403
331
  state.lastGroundedY = entity.body.translation().y;
@@ -410,9 +338,12 @@ var Platformer3DBehavior = class {
410
338
  state.falling = false;
411
339
  state.jumpCutApplied = false;
412
340
  state.jumpCutRampTimer = 0;
341
+ if (state.verticalVelocity < 0) {
342
+ state.verticalVelocity = 0;
343
+ }
413
344
  }
414
- if (velocity.y < -0.1 && !state.grounded) {
415
- if (state.jumping && velocity.y < 0) {
345
+ if (state.verticalVelocity < FALL_VELOCITY_THRESHOLD && !state.grounded) {
346
+ if (state.jumping) {
416
347
  state.jumping = false;
417
348
  state.falling = true;
418
349
  } else if (!state.jumping) {
@@ -428,15 +359,40 @@ var Platformer3DBehavior = class {
428
359
  if (!entity.platformer || !entity.$platformer || !entity.platformerState) {
429
360
  return;
430
361
  }
431
- const platformerEntity = entity;
432
- this.ensurePhysicsConfigured(platformerEntity);
433
- this.updateState(platformerEntity, delta);
434
- this.applyMovement(platformerEntity);
435
- this.handleJump(platformerEntity, delta);
436
- this.applyGravity(platformerEntity, delta);
362
+ const controller = this.ensurePhysicsConfigured(entity);
363
+ const collider = entity.collider;
364
+ if (!controller || !collider) return;
365
+ const input = entity.$platformer;
366
+ const movement = entity.platformer;
367
+ const state = entity.platformerState;
368
+ this.handleJump(entity, delta);
369
+ this.applyGravity(entity, delta);
370
+ const speed = input.run ? movement.runSpeed : movement.walkSpeed;
371
+ state.currentSpeed = speed;
372
+ _desired.x = input.moveX * speed * delta;
373
+ _desired.y = state.verticalVelocity * delta;
374
+ _desired.z = input.moveZ * speed * delta;
375
+ controller.computeColliderMovement(collider, _desired, QueryFilterFlags.EXCLUDE_SENSORS);
376
+ const corrected = controller.computedMovement();
377
+ if (_desired.y > 1e-9 && corrected.y < _desired.y * 0.5) {
378
+ state.verticalVelocity = 0;
379
+ }
380
+ const translation = entity.body.translation();
381
+ entity.body.setNextKinematicTranslation({
382
+ x: translation.x + corrected.x,
383
+ y: translation.y + corrected.y,
384
+ z: translation.z + corrected.z
385
+ });
386
+ this.updateState(entity, delta, controller.computedGrounded());
437
387
  }
438
388
  destroy() {
439
- this.gravityConfiguredUUIDs.clear();
389
+ const physicsWorld = this.world?.world;
390
+ if (physicsWorld) {
391
+ for (const controller of this.controllers.values()) {
392
+ physicsWorld.removeCharacterController(controller);
393
+ }
394
+ }
395
+ this.controllers.clear();
440
396
  }
441
397
  };
442
398
 
@@ -447,20 +403,19 @@ var defaultOptions = {
447
403
  jumpForce: 12,
448
404
  maxJumps: 1,
449
405
  gravity: 9.82,
450
- groundRayLength: 1,
451
- debugGroundProbe: false
406
+ slopeClimbAngle: 50,
407
+ slopeSlideAngle: 40,
408
+ autostep: { maxHeight: 0.3, minWidth: 0.1 },
409
+ snapToGroundDistance: 0.3,
410
+ characterOffset: 0.05
452
411
  };
453
412
  var PLATFORMER_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:platformer-3d");
454
413
  var Platformer3DBehaviorSystem = class {
455
- constructor(world, scene, wasmStage, getBehaviorLinks) {
456
- this.world = world;
457
- this.scene = scene;
414
+ constructor(world, wasmStage, getBehaviorLinks) {
458
415
  this.wasmStage = wasmStage;
459
416
  this.getBehaviorLinks = getBehaviorLinks;
460
- this.movementBehavior = new Platformer3DBehavior(world, scene);
417
+ this.movementBehavior = new Platformer3DSystem(world);
461
418
  }
462
- world;
463
- scene;
464
419
  wasmStage;
465
420
  getBehaviorLinks;
466
421
  movementBehavior;
@@ -522,12 +477,11 @@ var Platformer3DBehaviorSystem = class {
522
477
  this.attachedRuntimeSlots.clear();
523
478
  }
524
479
  };
525
- var Platformer3DBehavior2 = defineBehavior({
480
+ var Platformer3DBehavior = defineBehavior({
526
481
  name: "platformer-3d",
527
482
  defaultOptions,
528
483
  systemFactory: (ctx) => new Platformer3DBehaviorSystem(
529
- ctx.world,
530
- ctx.scene,
484
+ ctx.world ?? null,
531
485
  ctx.wasmStage ?? null,
532
486
  ctx.getBehaviorLinks
533
487
  ),
@@ -546,6 +500,7 @@ export {
546
500
  Platformer3DState,
547
501
  Platformer3DEvent,
548
502
  Platformer3DFSM,
549
- Platformer3DBehavior,
550
- Platformer3DBehavior2
503
+ Platformer3DSystem,
504
+ Platformer3DBehavior
551
505
  };
506
+ //# sourceMappingURL=chunk-FRJDQM23.js.map