@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.
- package/LICENSE +21 -0
- package/dist/{behavior-system-DYbx-x_-.d.ts → behavior-system-DSNek0W9.d.ts} +205 -29
- package/dist/{chunk-RER2IDPW.js → chunk-4URF65BR.js} +1 -0
- package/dist/chunk-4URF65BR.js.map +1 -0
- package/dist/{chunk-YYJP62QD.js → chunk-4V7TIRO2.js} +1 -0
- package/dist/chunk-4V7TIRO2.js.map +1 -0
- package/dist/{chunk-F7E23E26.js → chunk-4WH2ZN7P.js} +1 -0
- package/dist/chunk-4WH2ZN7P.js.map +1 -0
- package/dist/{chunk-VPZ32CCD.js → chunk-5SM5SH5O.js} +29 -28
- package/dist/chunk-5SM5SH5O.js.map +1 -0
- package/dist/{chunk-L76JG73P.js → chunk-5XZWTFGF.js} +7 -4
- package/dist/chunk-5XZWTFGF.js.map +1 -0
- package/dist/{chunk-HIBJDA5Z.js → chunk-64HKCSXD.js} +21 -17
- package/dist/chunk-64HKCSXD.js.map +1 -0
- package/dist/{chunk-WSKD7GY3.js → chunk-7JJEIADR.js} +1 -0
- package/dist/chunk-7JJEIADR.js.map +1 -0
- package/dist/{chunk-F6LFX4V3.js → chunk-BXP4K7RF.js} +3 -2
- package/dist/chunk-BXP4K7RF.js.map +1 -0
- package/dist/{chunk-2HKY6WF7.js → chunk-EIWQM6U3.js} +1 -0
- package/dist/chunk-EIWQM6U3.js.map +1 -0
- package/dist/{chunk-YDLO5M7S.js → chunk-EZNCCO4L.js} +1 -0
- package/dist/chunk-EZNCCO4L.js.map +1 -0
- package/dist/{chunk-T2P4JTQN.js → chunk-FRJDQM23.js} +110 -155
- package/dist/chunk-FRJDQM23.js.map +1 -0
- package/dist/{chunk-FHDYJ5WP.js → chunk-FTDZAKZW.js} +5 -17
- package/dist/chunk-FTDZAKZW.js.map +1 -0
- package/dist/{chunk-D53GNZXP.js → chunk-GFARAJV2.js} +6 -7
- package/dist/chunk-GFARAJV2.js.map +1 -0
- package/dist/{chunk-IQRG5BAZ.js → chunk-GTLA6LOJ.js} +18 -23
- package/dist/chunk-GTLA6LOJ.js.map +1 -0
- package/dist/{chunk-VO5J64DG.js → chunk-H4TJ7X4O.js} +4 -6
- package/dist/chunk-H4TJ7X4O.js.map +1 -0
- package/dist/{chunk-6UMC6BB5.js → chunk-HNESASBB.js} +7 -8
- package/dist/chunk-HNESASBB.js.map +1 -0
- package/dist/{chunk-4DVDFCVY.js → chunk-HZMY3TT4.js} +1 -0
- package/dist/chunk-HZMY3TT4.js.map +1 -0
- package/dist/{chunk-2HLZBWGD.js → chunk-IZJFUAXB.js} +1 -0
- package/dist/chunk-IZJFUAXB.js.map +1 -0
- package/dist/{chunk-UFHYR2LV.js → chunk-JXMF4NUI.js} +51 -2
- package/dist/chunk-JXMF4NUI.js.map +1 -0
- package/dist/{chunk-ZHBD65AZ.js → chunk-KDY5N6J4.js} +1 -0
- package/dist/chunk-KDY5N6J4.js.map +1 -0
- package/dist/chunk-KFFETUAL.js +40 -0
- package/dist/chunk-KFFETUAL.js.map +1 -0
- package/dist/chunk-LL4FLHIY.js +12 -0
- package/dist/chunk-LL4FLHIY.js.map +1 -0
- package/dist/{chunk-BC3IJYS7.js → chunk-MJFMNRMZ.js} +15 -15
- package/dist/chunk-MJFMNRMZ.js.map +1 -0
- package/dist/{chunk-WHKPWIQO.js → chunk-OHCPV2NT.js} +1 -0
- package/dist/chunk-OHCPV2NT.js.map +1 -0
- package/dist/{chunk-RQWWUML4.js → chunk-OTLSUYQQ.js} +2 -1
- package/dist/chunk-OTLSUYQQ.js.map +1 -0
- package/dist/{chunk-E4HTCQPK.js → chunk-PWF757B6.js} +7 -8
- package/dist/chunk-PWF757B6.js.map +1 -0
- package/dist/{chunk-4EWASZHB.js → chunk-QVCMJ4Q2.js} +1 -0
- package/dist/chunk-QVCMJ4Q2.js.map +1 -0
- package/dist/{chunk-FOOM42MK.js → chunk-RONH2KDI.js} +12 -13
- package/dist/chunk-RONH2KDI.js.map +1 -0
- package/dist/chunk-RTRFJVCZ.js +454 -0
- package/dist/chunk-RTRFJVCZ.js.map +1 -0
- package/dist/{chunk-IEA7F73P.js → chunk-UL6Q5HDP.js} +25 -2
- package/dist/chunk-UL6Q5HDP.js.map +1 -0
- package/dist/{chunk-K6CWKFHL.js → chunk-UYFOLI2X.js} +1 -0
- package/dist/chunk-UYFOLI2X.js.map +1 -0
- package/dist/{chunk-RD2YTTXY.js → chunk-V74N7D6Q.js} +9 -8
- package/dist/chunk-V74N7D6Q.js.map +1 -0
- package/dist/{chunk-ERS6SNA5.js → chunk-WOMHL23C.js} +2 -1
- package/dist/chunk-WOMHL23C.js.map +1 -0
- package/dist/{chunk-RHW3IDQX.js → chunk-WWVD5DR5.js} +1 -0
- package/dist/chunk-WWVD5DR5.js.map +1 -0
- package/dist/{chunk-SBACY5SU.js → chunk-WXXXJ22R.js} +14 -15
- package/dist/chunk-WXXXJ22R.js.map +1 -0
- package/dist/{chunk-6Y3GB76J.js → chunk-XLUJDKCT.js} +9 -8
- package/dist/chunk-XLUJDKCT.js.map +1 -0
- package/dist/{chunk-7Y6JVZ5H.js → chunk-XP3ASVGJ.js} +14 -10
- package/dist/chunk-XP3ASVGJ.js.map +1 -0
- package/dist/{chunk-7U4WFBWM.js → chunk-Y7YIAWPW.js} +11 -0
- package/dist/chunk-Y7YIAWPW.js.map +1 -0
- package/dist/{chunk-7IZ36Y5G.js → chunk-ZA43LPRM.js} +5 -24
- package/dist/chunk-ZA43LPRM.js.map +1 -0
- package/dist/{chunk-J5XLB24H.js → chunk-ZRQWSURL.js} +3 -2
- package/dist/chunk-ZRQWSURL.js.map +1 -0
- package/dist/cooldown.d.ts +2 -1
- package/dist/cooldown.js +3 -2
- package/dist/cooldown.js.map +1 -0
- package/dist/coordinators/boundary-ricochet-3d.d.ts +12 -5
- package/dist/coordinators/boundary-ricochet-3d.js +4 -2
- package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
- package/dist/coordinators/boundary-ricochet.d.ts +9 -7
- package/dist/coordinators/boundary-ricochet.js +4 -2
- package/dist/coordinators/boundary-ricochet.js.map +1 -0
- package/dist/coordinators/first-person-shooter.d.ts +9 -8
- package/dist/coordinators/first-person-shooter.js +4 -3
- package/dist/coordinators/first-person-shooter.js.map +1 -0
- package/dist/coordinators/multidirectional-space-shooter.d.ts +12 -9
- package/dist/coordinators/multidirectional-space-shooter.js +5 -4
- package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
- package/dist/coordinators/top-down-shooter.d.ts +9 -8
- package/dist/coordinators/top-down-shooter.js +5 -4
- package/dist/coordinators/top-down-shooter.js.map +1 -0
- package/dist/core.d.ts +4 -4
- package/dist/core.js +9 -36
- package/dist/core.js.map +1 -0
- package/dist/destructible-3d.d.ts +2 -1
- package/dist/destructible-3d.js +4 -3
- package/dist/destructible-3d.js.map +1 -0
- package/dist/destructible-prebake.js +2 -1
- package/dist/destructible-prebake.js.map +1 -0
- package/dist/first-person.d.ts +12 -12
- package/dist/first-person.js +12 -11
- package/dist/first-person.js.map +1 -0
- package/dist/index.d.ts +37 -14
- package/dist/index.js +85 -55
- package/dist/index.js.map +1 -0
- package/dist/jumper-2d.d.ts +7 -6
- package/dist/jumper-2d.js +8 -7
- package/dist/jumper-2d.js.map +1 -0
- package/dist/jumper-3d.d.ts +12 -11
- package/dist/jumper-3d.js +9 -8
- package/dist/jumper-3d.js.map +1 -0
- package/dist/{moveable-BCRpjAQb.d.ts → moveable-BLTHO7Jq.d.ts} +2 -78
- package/dist/particle-emitter/presets.js +2 -1
- package/dist/particle-emitter/presets.js.map +1 -0
- package/dist/particle-emitter.d.ts +1 -1
- package/dist/particle-emitter.js +5 -4
- package/dist/particle-emitter.js.map +1 -0
- package/dist/platformer-2d.d.ts +306 -0
- package/dist/platformer-2d.js +23 -0
- package/dist/platformer-2d.js.map +1 -0
- package/dist/platformer-3d.d.ts +74 -87
- package/dist/platformer-3d.js +7 -6
- package/dist/platformer-3d.js.map +1 -0
- package/dist/ricochet-2d.d.ts +1 -1
- package/dist/ricochet-2d.js +5 -4
- package/dist/ricochet-2d.js.map +1 -0
- package/dist/ricochet-3d.d.ts +1 -1
- package/dist/ricochet-3d.js +5 -4
- package/dist/ricochet-3d.js.map +1 -0
- package/dist/runtime-2d.d.ts +93 -2
- package/dist/runtime-2d.js +146 -22
- package/dist/runtime-2d.js.map +1 -0
- package/dist/screen-visibility.d.ts +2 -1
- package/dist/screen-visibility.js +3 -2
- package/dist/screen-visibility.js.map +1 -0
- package/dist/screen-wrap.d.ts +2 -1
- package/dist/screen-wrap.js +5 -4
- package/dist/screen-wrap.js.map +1 -0
- package/dist/shooter-2d.d.ts +5 -3
- package/dist/shooter-2d.js +5 -4
- package/dist/shooter-2d.js.map +1 -0
- package/dist/shooter-fire-DGripl0z.d.ts +55 -0
- package/dist/thruster.d.ts +8 -18
- package/dist/thruster.js +9 -8
- package/dist/thruster.js.map +1 -0
- package/dist/top-down-movement.d.ts +7 -4
- package/dist/top-down-movement.js +8 -7
- package/dist/top-down-movement.js.map +1 -0
- package/dist/{use-behavior-D_82jAL3.d.ts → use-behavior-h9-T5FSv.d.ts} +1 -1
- package/dist/world-boundary-2d.d.ts +2 -1
- package/dist/world-boundary-2d.js +6 -5
- package/dist/world-boundary-2d.js.map +1 -0
- package/dist/world-boundary-3d.d.ts +2 -1
- package/dist/world-boundary-3d.js +6 -5
- package/dist/world-boundary-3d.js.map +1 -0
- package/package.json +8 -7
- package/dist/chunk-23HQH3GJ.js +0 -34
- package/dist/chunk-K4UBXSZL.js +0 -175
- package/dist/runtime-pong.d.ts +0 -92
- 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"]}
|
|
@@ -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":[]}
|
|
@@ -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-
|
|
4
|
+
} from "./chunk-4URF65BR.js";
|
|
5
5
|
import {
|
|
6
6
|
defineBehavior
|
|
7
|
-
} from "./chunk-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
189
|
-
var
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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:
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
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
|
-
|
|
245
|
-
if (
|
|
246
|
-
|
|
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
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
|
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
|
-
|
|
303
|
-
if (velocity.y > 0) {
|
|
265
|
+
if (state.verticalVelocity > 0) {
|
|
304
266
|
const stepT = Math.min(delta / state.jumpCutRampTimer, 1);
|
|
305
|
-
const targetY =
|
|
306
|
-
|
|
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.
|
|
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
|
-
*
|
|
294
|
+
* Integrate gravity into `state.verticalVelocity`.
|
|
336
295
|
*
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
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)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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
|
|
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 =
|
|
324
|
+
isGrounded = computedGrounded && canLand;
|
|
380
325
|
} else {
|
|
381
|
-
isGrounded =
|
|
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 (
|
|
415
|
-
if (state.jumping
|
|
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
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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.
|
|
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
|
-
|
|
451
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
550
|
-
|
|
503
|
+
Platformer3DSystem,
|
|
504
|
+
Platformer3DBehavior
|
|
551
505
|
};
|
|
506
|
+
//# sourceMappingURL=chunk-FRJDQM23.js.map
|