@zylem/behaviors 0.3.0 → 0.3.1
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/{chunk-K4UBXSZL.js → chunk-2C3Z5GE7.js} +2 -1
- package/dist/chunk-2C3Z5GE7.js.map +1 -0
- package/dist/{chunk-BC3IJYS7.js → chunk-2CLT36VB.js} +5 -4
- package/dist/chunk-2CLT36VB.js.map +1 -0
- package/dist/{chunk-23HQH3GJ.js → chunk-3PYGRHAL.js} +2 -1
- package/dist/chunk-3PYGRHAL.js.map +1 -0
- package/dist/{chunk-6UMC6BB5.js → chunk-4I6E6DGV.js} +5 -4
- package/dist/chunk-4I6E6DGV.js.map +1 -0
- package/dist/{chunk-RER2IDPW.js → chunk-4URF65BR.js} +1 -0
- package/dist/chunk-4URF65BR.js.map +1 -0
- package/dist/{chunk-IEA7F73P.js → chunk-6C6NXNEW.js} +2 -1
- package/dist/chunk-6C6NXNEW.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-6Y3GB76J.js → chunk-ARJWUNRE.js} +4 -3
- package/dist/chunk-ARJWUNRE.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-F7E23E26.js → chunk-DYLH6K7B.js} +1 -0
- package/dist/chunk-DYLH6K7B.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-FOOM42MK.js → chunk-F3KRX2V4.js} +6 -5
- package/dist/chunk-F3KRX2V4.js.map +1 -0
- package/dist/{chunk-7IZ36Y5G.js → chunk-FPTWVCPN.js} +3 -2
- package/dist/chunk-FPTWVCPN.js.map +1 -0
- package/dist/{chunk-7Y6JVZ5H.js → chunk-GCNRXAKH.js} +2 -1
- package/dist/chunk-GCNRXAKH.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-7U4WFBWM.js → chunk-ID5QJYF5.js} +1 -0
- package/dist/chunk-ID5QJYF5.js.map +1 -0
- package/dist/{chunk-T2P4JTQN.js → chunk-JAN34G6S.js} +3 -2
- package/dist/chunk-JAN34G6S.js.map +1 -0
- package/dist/{chunk-J5XLB24H.js → chunk-K3UNLQ7W.js} +2 -1
- package/dist/chunk-K3UNLQ7W.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-RD2YTTXY.js → chunk-KOZUNIIE.js} +4 -3
- package/dist/chunk-KOZUNIIE.js.map +1 -0
- package/dist/{chunk-2HLZBWGD.js → chunk-KS72RZHX.js} +1 -0
- package/dist/chunk-KS72RZHX.js.map +1 -0
- package/dist/{chunk-4EWASZHB.js → chunk-LD5SMIB3.js} +1 -0
- package/dist/chunk-LD5SMIB3.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-HIBJDA5Z.js → chunk-OYWFPIHF.js} +5 -4
- package/dist/chunk-OYWFPIHF.js.map +1 -0
- package/dist/{chunk-FHDYJ5WP.js → chunk-RTRVBEIB.js} +3 -2
- package/dist/chunk-RTRVBEIB.js.map +1 -0
- package/dist/{chunk-RQWWUML4.js → chunk-RTVRUNYR.js} +1 -0
- package/dist/chunk-RTVRUNYR.js.map +1 -0
- package/dist/{chunk-IQRG5BAZ.js → chunk-SS7ELMJ7.js} +5 -4
- package/dist/chunk-SS7ELMJ7.js.map +1 -0
- package/dist/{chunk-L76JG73P.js → chunk-STCCNLPC.js} +4 -3
- package/dist/chunk-STCCNLPC.js.map +1 -0
- package/dist/{chunk-UFHYR2LV.js → chunk-SVLNF434.js} +1 -0
- package/dist/chunk-SVLNF434.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-VO5J64DG.js → chunk-VAN4WW3F.js} +3 -2
- package/dist/chunk-VAN4WW3F.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-E4HTCQPK.js → chunk-XG2YMCJW.js} +5 -4
- package/dist/chunk-XG2YMCJW.js.map +1 -0
- package/dist/{chunk-D53GNZXP.js → chunk-XIJNE67Y.js} +4 -3
- package/dist/chunk-XIJNE67Y.js.map +1 -0
- package/dist/{chunk-YYJP62QD.js → chunk-Y6UJOUE5.js} +1 -0
- package/dist/chunk-Y6UJOUE5.js.map +1 -0
- package/dist/{chunk-SBACY5SU.js → chunk-YUO6SKJD.js} +6 -5
- package/dist/chunk-YUO6SKJD.js.map +1 -0
- package/dist/{chunk-VPZ32CCD.js → chunk-ZPSAXX73.js} +4 -3
- package/dist/chunk-ZPSAXX73.js.map +1 -0
- package/dist/cooldown.js +3 -2
- package/dist/cooldown.js.map +1 -0
- package/dist/coordinators/boundary-ricochet-3d.js +3 -2
- package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
- package/dist/coordinators/boundary-ricochet.js +3 -2
- package/dist/coordinators/boundary-ricochet.js.map +1 -0
- 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.js +5 -4
- package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
- package/dist/coordinators/top-down-shooter.js +5 -4
- package/dist/coordinators/top-down-shooter.js.map +1 -0
- package/dist/core.js +7 -6
- package/dist/core.js.map +1 -0
- 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.js +7 -6
- package/dist/first-person.js.map +1 -0
- package/dist/index.js +39 -38
- package/dist/index.js.map +1 -0
- package/dist/jumper-2d.js +6 -5
- package/dist/jumper-2d.js.map +1 -0
- package/dist/jumper-3d.js +7 -6
- package/dist/jumper-3d.js.map +1 -0
- package/dist/particle-emitter/presets.js +2 -1
- package/dist/particle-emitter/presets.js.map +1 -0
- package/dist/particle-emitter.js +5 -4
- package/dist/particle-emitter.js.map +1 -0
- package/dist/platformer-3d.js +4 -3
- package/dist/platformer-3d.js.map +1 -0
- package/dist/ricochet-2d.js +5 -4
- package/dist/ricochet-2d.js.map +1 -0
- package/dist/ricochet-3d.js +5 -4
- package/dist/ricochet-3d.js.map +1 -0
- package/dist/runtime-2d.js +3 -2
- package/dist/runtime-2d.js.map +1 -0
- package/dist/runtime-pong.js +3 -2
- package/dist/runtime-pong.js.map +1 -0
- package/dist/screen-visibility.js +3 -2
- package/dist/screen-visibility.js.map +1 -0
- package/dist/screen-wrap.js +5 -4
- package/dist/screen-wrap.js.map +1 -0
- package/dist/shooter-2d.js +5 -4
- package/dist/shooter-2d.js.map +1 -0
- package/dist/thruster.js +6 -5
- package/dist/thruster.js.map +1 -0
- package/dist/top-down-movement.js +6 -5
- package/dist/top-down-movement.js.map +1 -0
- package/dist/world-boundary-2d.js +6 -5
- package/dist/world-boundary-2d.js.map +1 -0
- package/dist/world-boundary-3d.js +6 -5
- package/dist/world-boundary-3d.js.map +1 -0
- package/package.json +4 -3
|
@@ -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/jumper-3d/components.ts"],"sourcesContent":["/**\n * Jumper 3D ECS Components\n *\n * Type definitions and factory functions for the 3D jump behavior system.\n *\n * - JumpConfig3D: tunable parameters (stored as the capability component)\n * - JumpInput3D: per-tick intent written by the player/AI controller\n * - JumpContext3D: per-tick snapshot provided by the system adapter\n * - JumpState3D: internal runtime state owned by the behavior\n */\n\nimport type { Vector3 } from 'three';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Vec3-like interface for cross-library compatibility\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Vec3Like {\n\tx: number;\n\ty: number;\n\tz: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpConfig3D (capability / configuration)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpConfig3D {\n\t/** Desired peak height in world units */\n\tjumpHeight: number;\n\t/** Gravity magnitude (positive, e.g. 20) */\n\tgravity: number;\n\t/** Terminal fall speed magnitude (optional) */\n\tmaxFallSpeed?: number;\n\n\t/** 1 = single jump, 2 = double, etc. */\n\tmaxJumps: number;\n\t/** Reset jump counter when grounded (usually true) */\n\tresetJumpsOnGround: boolean;\n\t/** Reset jump counter on wall contact (future wall-jump support) */\n\tresetJumpsOnWall?: boolean;\n\n\t/** Grace period after leaving ground where first jump is still allowed (ms) */\n\tcoyoteTimeMs: number;\n\t/** Queue a jump press this many ms before landing (ms) */\n\tjumpBufferMs: number;\n\t/** Optional cooldown between consecutive jumps (ms) */\n\tminTimeBetweenJumpsMs?: number;\n\n\t/** Variable jump height via early release */\n\tvariableJump?: {\n\t\tenabled: boolean;\n\t\t/** Gravity multiplier applied when jump is released early while ascending */\n\t\tcutGravityMultiplier: number;\n\t\t/** Max hold duration before the cut triggers automatically (ms, optional) */\n\t\tmaxHoldMs?: number;\n\t};\n\n\t/** Optional planar (XZ) launch / air-control overrides */\n\tplanar?: {\n\t\t/** One-time planar speed applied at takeoff */\n\t\tlaunchPlanarSpeed?: number;\n\t\t/** If true, preserve current planar speed instead of replacing it */\n\t\tpreservePlanarSpeed?: boolean;\n\t\tairControl?: {\n\t\t\tmaxPlanarSpeed: number;\n\t\t\t/** Acceleration per second while airborne */\n\t\t\tacceleration: number;\n\t\t\t/** Deceleration per second when no input */\n\t\t\tdeceleration: number;\n\t\t};\n\t};\n\n\t/** Snappier descent tuning */\n\tfall?: {\n\t\t/** Gravity multiplier while falling (e.g. 1.5-2.5) */\n\t\tfallGravityMultiplier: number;\n\t\t/** Additional multiplier when fast-fall input is held */\n\t\tfastFallMultiplier?: number;\n\t};\n}\n\nexport function createJumpConfig3D(\n\toptions: Partial<JumpConfig3D> = {},\n): JumpConfig3D {\n\treturn {\n\t\tjumpHeight: options.jumpHeight ?? 2.5,\n\t\tgravity: options.gravity ?? 20,\n\t\tmaxFallSpeed: options.maxFallSpeed,\n\t\tmaxJumps: options.maxJumps ?? 1,\n\t\tresetJumpsOnGround: options.resetJumpsOnGround ?? true,\n\t\tresetJumpsOnWall: options.resetJumpsOnWall,\n\t\tcoyoteTimeMs: options.coyoteTimeMs ?? 100,\n\t\tjumpBufferMs: options.jumpBufferMs ?? 80,\n\t\tminTimeBetweenJumpsMs: options.minTimeBetweenJumpsMs,\n\t\tvariableJump: options.variableJump,\n\t\tplanar: options.planar,\n\t\tfall: options.fall,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpInput3D (intent)\n// Written by: Player controller, AI controller\n// Read by: Jumper3DBehavior\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpInput3D {\n\t/** True on the frame the jump button is first pressed (rising edge) */\n\tjumpPressed: boolean;\n\t/** True while the jump button is held down */\n\tjumpHeld: boolean;\n\t/** True on the frame the jump button is released (falling edge) */\n\tjumpReleased: boolean;\n\t/** Desired planar direction in world space (camera-relative), optional */\n\tmoveDirWorld?: Vec3Like;\n\t/** Hold to drop faster (e.g. crouch / down input) */\n\tfastFall?: boolean;\n}\n\nexport function createJumpInput3D(): JumpInput3D {\n\treturn {\n\t\tjumpPressed: false,\n\t\tjumpHeld: false,\n\t\tjumpReleased: false,\n\t\tmoveDirWorld: undefined,\n\t\tfastFall: false,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpContext3D (per-tick snapshot from entity / controller)\n// Built by the system adapter — never written to by user code.\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpContext3D {\n\t/** Frame delta in seconds */\n\tdt: number;\n\t/** World up direction (usually 0,1,0) */\n\tup: Vec3Like;\n\t/** Current vertical (Y) velocity of the entity */\n\tvelocityY: number;\n\t/** Current horizontal velocity of the entity (read from body) */\n\thorizontalVelocity: { x: number; z: number };\n\t/** Whether the entity is on the ground */\n\tisGrounded: boolean;\n\t/** Surface normal at ground contact (optional) */\n\tgroundNormal?: Vec3Like;\n\t/** Time since entity was last grounded (ms) */\n\ttimeSinceGroundedMs: number;\n\n\t/** Set only the vertical (Y) component of velocity */\n\tsetVerticalVelocity(y: number): void;\n\t/** Set only the horizontal (X/Z) components of velocity */\n\tsetHorizontalVelocity(x: number, z: number): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpState3D (internal runtime state)\n// Owned and mutated exclusively by Jumper3DBehavior.tick()\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpState3D {\n\t/** Number of jumps consumed since last reset */\n\tjumpsUsed: number;\n\t/** Timestamp (ms) of the most recent jump execution */\n\tlastJumpTimeMs: number;\n\t/** Remaining ms in the jump-buffer window (counts down) */\n\tbufferedJumpMs: number;\n\t/** Remaining ms in the coyote-time window (counts down) */\n\tcoyoteMs: number;\n\t/** True while the entity is in a jump arc (ascending phase) */\n\tisJumping: boolean;\n\t/** Elapsed ms since jump button was first held (for variable jump) */\n\tjumpHoldMs: number;\n\t/** Whether the variable-jump cut has already been applied this jump */\n\tjumpCutApplied: boolean;\n}\n\nexport function createJumpState3D(): JumpState3D {\n\treturn {\n\t\tjumpsUsed: 0,\n\t\tlastJumpTimeMs: 0,\n\t\tbufferedJumpMs: 0,\n\t\tcoyoteMs: 0,\n\t\tisJumping: false,\n\t\tjumpHoldMs: 0,\n\t\tjumpCutApplied: false,\n\t};\n}\n"],"mappings":";AAkFO,SAAS,mBACf,UAAiC,CAAC,GACnB;AACf,SAAO;AAAA,IACN,YAAY,QAAQ,cAAc;AAAA,IAClC,SAAS,QAAQ,WAAW;AAAA,IAC5B,cAAc,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY;AAAA,IAC9B,oBAAoB,QAAQ,sBAAsB;AAAA,IAClD,kBAAkB,QAAQ;AAAA,IAC1B,cAAc,QAAQ,gBAAgB;AAAA,IACtC,cAAc,QAAQ,gBAAgB;AAAA,IACtC,uBAAuB,QAAQ;AAAA,IAC/B,cAAc,QAAQ;AAAA,IACtB,QAAQ,QAAQ;AAAA,IAChB,MAAM,QAAQ;AAAA,EACf;AACD;AAqBO,SAAS,oBAAiC;AAChD,SAAO;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,EACX;AACD;AAmDO,SAAS,oBAAiC;AAChD,SAAO;AAAA,IACN,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,gBAAgB;AAAA,EACjB;AACD;","names":[]}
|
|
@@ -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":[]}
|
|
@@ -2,22 +2,22 @@ import {
|
|
|
2
2
|
createJumpConfig3D,
|
|
3
3
|
createJumpInput3D,
|
|
4
4
|
createJumpState3D
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DYLH6K7B.js";
|
|
6
6
|
import {
|
|
7
7
|
GroundProbe3D,
|
|
8
8
|
getGroundAnchorOffsetY,
|
|
9
9
|
getGroundSnapTargetY
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SVLNF434.js";
|
|
11
11
|
import {
|
|
12
12
|
setVelocityIntent
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-RTVRUNYR.js";
|
|
14
14
|
import {
|
|
15
15
|
SyncStateMachine,
|
|
16
16
|
t
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-4URF65BR.js";
|
|
18
18
|
import {
|
|
19
19
|
defineBehavior
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-EZNCCO4L.js";
|
|
21
21
|
|
|
22
22
|
// src/lib/behaviors/jumper-3d/jumper-3d.behavior.ts
|
|
23
23
|
function jumpVelocityFromHeight(gravity, height) {
|
|
@@ -454,3 +454,4 @@ export {
|
|
|
454
454
|
Jumper3DFSM,
|
|
455
455
|
Jumper3D
|
|
456
456
|
};
|
|
457
|
+
//# sourceMappingURL=chunk-F3KRX2V4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/jumper-3d/jumper-3d.behavior.ts","../src/lib/behaviors/jumper-3d/jumper-3d-fsm.ts","../src/lib/behaviors/jumper-3d/jumper-3d.descriptor.ts"],"sourcesContent":["/**\n * Jumper 3D Behavior — Pure Jump Physics\n *\n * A stateless tick function that receives configuration, input, context, and\n * state, then applies jump physics through the context's velocity helpers.\n *\n * Vertical velocity (Y) is owned exclusively by this behavior.\n * Horizontal velocity (X/Z) is only touched when airborne planar control\n * is configured; otherwise the movement controller owns X/Z.\n */\n\nimport type {\n\tJumpConfig3D,\n\tJumpInput3D,\n\tJumpContext3D,\n\tJumpState3D,\n} from './components';\n\n/** v = sqrt(2 * g * h) */\nfunction jumpVelocityFromHeight(gravity: number, height: number): number {\n\treturn Math.sqrt(2 * gravity * height);\n}\n\nfunction planarSpeed(x: number, z: number): number {\n\treturn Math.sqrt(x * x + z * z);\n}\n\nfunction normalizeMut(v: { x: number; y: number; z: number }): number {\n\tconst len = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);\n\tif (len > 1e-6) {\n\t\tv.x /= len;\n\t\tv.y /= len;\n\t\tv.z /= len;\n\t}\n\treturn len;\n}\n\nexport class Jumper3DBehavior {\n\t/**\n\t * Advance the jump system by one frame.\n\t *\n\t * Call order within a frame:\n\t * 1. Movement controller writes X/Z via transformStore.dirty.velocityX/Z.\n\t * 2. `tick()` writes Y via ctx.setVerticalVelocity().\n\t * (Optionally writes X/Z when airborne planar control is active.)\n\t */\n\ttick(\n\t\tconfig: JumpConfig3D,\n\t\tinput: JumpInput3D,\n\t\tctx: JumpContext3D,\n\t\tstate: JumpState3D,\n\t): JumperTickResult {\n\t\tconst dtMs = ctx.dt * 1000;\n\t\tconst now = performance.now();\n\t\tlet event: JumperTickEvent = JumperTickEvent.None;\n\t\tlet jumpedThisFrame = false;\n\n\t\t// ── 1. Ground-contact bookkeeping ──────────────────────────────────\n\t\tif (ctx.isGrounded) {\n\t\t\tstate.coyoteMs = config.coyoteTimeMs;\n\t\t\tif (config.resetJumpsOnGround) {\n\t\t\t\tstate.jumpsUsed = 0;\n\t\t\t}\n\t\t\tif (state.isJumping) {\n\t\t\t\tstate.isJumping = false;\n\t\t\t\tstate.jumpCutApplied = false;\n\t\t\t\tevent = JumperTickEvent.Land;\n\t\t\t}\n\t\t} else {\n\t\t\tstate.coyoteMs = Math.max(0, state.coyoteMs - dtMs);\n\t\t}\n\n\t\t// ── 2. Jump buffer ─────────────────────────────────────────────────\n\t\tif (input.jumpPressed) {\n\t\t\tstate.bufferedJumpMs = config.jumpBufferMs;\n\t\t} else {\n\t\t\tstate.bufferedJumpMs = Math.max(0, state.bufferedJumpMs - dtMs);\n\t\t}\n\n\t\t// ── 3. Variable-jump hold tracking ─────────────────────────────────\n\t\tif (state.isJumping && input.jumpHeld) {\n\t\t\tstate.jumpHoldMs += dtMs;\n\t\t}\n\n\t\t// ── 4. Jump eligibility & execution ────────────────────────────────\n\t\tconst wantsJump = state.bufferedJumpMs > 0;\n\n\t\tconst isFirstJump =\n\t\t\tctx.isGrounded || (state.coyoteMs > 0 && state.jumpsUsed === 0);\n\t\tconst hasAirJumps = state.jumpsUsed > 0 && state.jumpsUsed < config.maxJumps;\n\t\tconst canJump = isFirstJump || hasAirJumps;\n\n\t\t\tconst cooldownOk =\n\t\t\t\tconfig.minTimeBetweenJumpsMs == null ||\n\t\t\t\tnow - state.lastJumpTimeMs >= config.minTimeBetweenJumpsMs;\n\n\t\t\tif (wantsJump && canJump && cooldownOk) {\n\t\t\t\tconst vy = jumpVelocityFromHeight(config.gravity, config.jumpHeight);\n\n\t\t\t\tctx.setVerticalVelocity(vy);\n\t\t\t\tjumpedThisFrame = true;\n\n\t\t\tif (config.planar?.launchPlanarSpeed != null && !config.planar.preservePlanarSpeed) {\n\t\t\t\tconst dir = input.moveDirWorld;\n\t\t\t\tif (dir && (Math.abs(dir.x) > 1e-6 || Math.abs(dir.z) > 1e-6)) {\n\t\t\t\t\tconst d = { x: dir.x, y: 0, z: dir.z };\n\t\t\t\t\tnormalizeMut(d);\n\t\t\t\t\tctx.setHorizontalVelocity(\n\t\t\t\t\t\td.x * config.planar.launchPlanarSpeed,\n\t\t\t\t\t\td.z * config.planar.launchPlanarSpeed,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.jumpsUsed++;\n\t\t\tstate.lastJumpTimeMs = now;\n\t\t\tstate.bufferedJumpMs = 0;\n\t\t\tstate.coyoteMs = 0;\n\t\t\tstate.isJumping = true;\n\t\t\tstate.jumpHoldMs = 0;\n\t\t\tstate.jumpCutApplied = false;\n\n\t\t\tevent = JumperTickEvent.Jump;\n\t\t}\n\n\t\t// ── 5. Gravity (with variable-jump and fall multipliers) ───────────\n\t\t// Treat a jump-launch frame as airborne so we don't immediately clamp\n\t\t// the freshly applied jump velocity back to zero.\n\t\tif (!ctx.isGrounded || jumpedThisFrame) {\n\t\t\tlet gravityMul = 1;\n\t\t\tconst vy = ctx.velocityY;\n\t\t\tconst isFalling = vy < 0;\n\n\t\t\tif (isFalling) {\n\t\t\t\tgravityMul = config.fall?.fallGravityMultiplier ?? 1;\n\t\t\t\tif (input.fastFall && config.fall?.fastFallMultiplier != null) {\n\t\t\t\t\tgravityMul *= config.fall.fastFallMultiplier;\n\t\t\t\t}\n\t\t\t\tif (event !== JumperTickEvent.Land) {\n\t\t\t\t\tevent = JumperTickEvent.Fall;\n\t\t\t\t}\n\t\t\t} else if (state.isJumping) {\n\t\t\t\tconst vj = config.variableJump;\n\t\t\t\tif (vj?.enabled && !state.jumpCutApplied) {\n\t\t\t\t\tconst holdExpired =\n\t\t\t\t\t\tvj.maxHoldMs != null && state.jumpHoldMs >= vj.maxHoldMs;\n\t\t\t\t\tif (!input.jumpHeld || holdExpired) {\n\t\t\t\t\t\tgravityMul = vj.cutGravityMultiplier;\n\t\t\t\t\t\tstate.jumpCutApplied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet newVy = ctx.velocityY - config.gravity * gravityMul * ctx.dt;\n\n\t\t\tif (config.maxFallSpeed != null) {\n\t\t\t\tnewVy = Math.max(-config.maxFallSpeed, newVy);\n\t\t\t}\n\n\t\t\tctx.setVerticalVelocity(newVy);\n\t\t} else {\n\t\t\t// Grounded: clamp Y to 0 so the entity doesn't drift\n\t\t\tctx.setVerticalVelocity(0);\n\t\t}\n\n\t\t// ── 6. Airborne planar control ─────────────────────────────────────\n\t\tconst airCtrl = config.planar?.airControl;\n\t\tif (airCtrl && !ctx.isGrounded) {\n\t\t\tconst dir = input.moveDirWorld;\n\t\t\tconst hasDir = dir && (Math.abs(dir.x) > 1e-6 || Math.abs(dir.z) > 1e-6);\n\n\t\t\tlet vx = ctx.horizontalVelocity.x;\n\t\t\tlet vz = ctx.horizontalVelocity.z;\n\n\t\t\tif (hasDir) {\n\t\t\t\tconst d = { x: dir!.x, y: 0, z: dir!.z };\n\t\t\t\tnormalizeMut(d);\n\n\t\t\t\tvx += d.x * airCtrl.acceleration * ctx.dt;\n\t\t\t\tvz += d.z * airCtrl.acceleration * ctx.dt;\n\n\t\t\t\tconst speed = Math.sqrt(vx * vx + vz * vz);\n\t\t\t\tif (speed > airCtrl.maxPlanarSpeed) {\n\t\t\t\t\tconst scale = airCtrl.maxPlanarSpeed / speed;\n\t\t\t\t\tvx *= scale;\n\t\t\t\t\tvz *= scale;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst speed = planarSpeed(vx, vz);\n\t\t\t\tif (speed > 1e-6) {\n\t\t\t\t\tconst decel = Math.min(airCtrl.deceleration * ctx.dt, speed);\n\t\t\t\t\tconst scale = (speed - decel) / speed;\n\t\t\t\t\tvx *= scale;\n\t\t\t\t\tvz *= scale;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tctx.setHorizontalVelocity(vx, vz);\n\t\t}\n\n\t\treturn { event };\n\t}\n}\n\n/** Events emitted by a single tick (used by FSM). */\nexport enum JumperTickEvent {\n\tNone = 'none',\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface JumperTickResult {\n\tevent: JumperTickEvent;\n}\n","/**\n * Jumper 3D Finite State Machine\n *\n * Three high-level states driven by events emitted from the behavior tick:\n * Grounded ──Jump──▶ Jumping\n * Grounded ──Fall──▶ Falling (walked off a ledge)\n * Jumping ──Fall──▶ Falling (apex / descending)\n * Jumping ──Jump──▶ Jumping (multi-jump)\n * Jumping ──Land──▶ Grounded (rare — very short hop)\n * Falling ──Land──▶ Grounded\n * Falling ──Jump──▶ Jumping (air-jump while falling)\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { JumpState3D } from './components';\n\nexport enum Jumper3DState {\n\tGrounded = 'grounded',\n\tJumping = 'jumping',\n\tFalling = 'falling',\n}\n\nexport enum Jumper3DEvent {\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface Jumper3DFSMContext {\n\tstate: JumpState3D;\n}\n\nexport class Jumper3DFSM {\n\tmachine: SyncStateMachine<Jumper3DState, Jumper3DEvent, never>;\n\n\tconstructor(private ctx: Jumper3DFSMContext) {\n\t\tthis.machine = new SyncStateMachine<Jumper3DState, Jumper3DEvent, never>(\n\t\t\tJumper3DState.Grounded,\n\t\t\t[\n\t\t\t\t// Grounded\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\n\t\t\t\t// Jumping\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\n\t\t\t\t// Falling\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t],\n\t\t);\n\t}\n\n\tgetState(): Jumper3DState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: Jumper3DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\tisJumping(): boolean {\n\t\treturn this.getState() === Jumper3DState.Jumping;\n\t}\n\n\tisFalling(): boolean {\n\t\treturn this.getState() === Jumper3DState.Falling;\n\t}\n\n\tisGrounded(): boolean {\n\t\treturn this.getState() === Jumper3DState.Grounded;\n\t}\n\n\tgetJumpsUsed(): number {\n\t\treturn this.ctx.state.jumpsUsed;\n\t}\n\n\t/**\n\t * Translate a tick event into an FSM dispatch.\n\t * Also handles the implicit Grounded→Falling transition when the entity\n\t * is no longer grounded but no explicit event was emitted (e.g. walked\n\t * off a ledge without jumping).\n\t */\n\tapplyTickEvent(tickEvent: string, isGrounded: boolean): void {\n\t\tswitch (tickEvent) {\n\t\t\tcase 'jump':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Jump);\n\t\t\t\tbreak;\n\t\t\tcase 'fall':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\tbreak;\n\t\t\tcase 'land':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// No explicit event — detect implicit fall\n\t\t\t\tif (!isGrounded && this.getState() === Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\t}\n\t\t\t\tif (isGrounded && this.getState() !== Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n","/**\n * Jumper 3D Behavior Descriptor\n *\n * Type-safe descriptor for the jumper-3d behavior system.\n * Provides `entity.use()` API for composable 3D jumping.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { setVelocityIntent } from '../../actions/capabilities/velocity-intents';\nimport { Jumper3DBehavior } from './jumper-3d.behavior';\nimport { Jumper3DFSM, Jumper3DState } from './jumper-3d-fsm';\nimport {\n\tGroundProbe3D,\n\tgetGroundAnchorOffsetY,\n\tgetGroundSnapTargetY,\n\ttype GroundProbeSupportHit,\n} from '../shared/ground-probe-3d';\nimport {\n\tcreateJumpConfig3D,\n\tcreateJumpInput3D,\n\tcreateJumpState3D,\n\ttype JumpConfig3D,\n\ttype JumpInput3D,\n\ttype JumpState3D,\n\ttype JumpContext3D,\n} from './components';\nimport type { WasmStageRuntime } from '../../runtime/wasm-stage-runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Options exposed through entity.use()\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DBehaviorOptions {\n\t/** Desired peak height in world units (default: 2.5) */\n\tjumpHeight?: number;\n\t/** Gravity magnitude applied by the behavior (default: 20) */\n\tgravity?: number;\n\t/** Terminal fall speed (optional) */\n\tmaxFallSpeed?: number;\n\t/** Max concurrent jumps, 1 = single, 2 = double, etc. (default: 1) */\n\tmaxJumps?: number;\n\t/** Reset jump counter on ground (default: true) */\n\tresetJumpsOnGround?: boolean;\n\t/** Reset jump counter on wall contact (default: undefined) */\n\tresetJumpsOnWall?: boolean;\n\t/** Coyote time in ms (default: 100) */\n\tcoyoteTimeMs?: number;\n\t/** Jump buffer in ms (default: 80) */\n\tjumpBufferMs?: number;\n\t/** Min cooldown between jumps in ms (optional) */\n\tminTimeBetweenJumpsMs?: number;\n\t/** Variable jump height config (optional) */\n\tvariableJump?: JumpConfig3D['variableJump'];\n\t/** Planar control config (optional) */\n\tplanar?: JumpConfig3D['planar'];\n\t/** Fall tuning (optional) */\n\tfall?: JumpConfig3D['fall'];\n\t/** Ground-detection ray length (default: 1.0) */\n\tgroundRayLength?: number;\n\t/** Max support distance that counts as grounded and can snap to ground */\n\tsnapToGroundDistance?: number;\n\t/** Enable debug visualization for ground probe rays (default: false) */\n\tdebugGroundProbe?: boolean;\n}\n\nconst defaultOptions: Jumper3DBehaviorOptions = {\n\tjumpHeight: 2.5,\n\tgravity: 20,\n\tmaxJumps: 1,\n\tresetJumpsOnGround: true,\n\tcoyoteTimeMs: 100,\n\tjumpBufferMs: 80,\n\tgroundRayLength: 1.0,\n\tdebugGroundProbe: false,\n};\n\nconst JUMPER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:jumper-3d');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Entity shape expected by the system\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DEntity {\n\tuuid: string;\n\tbody: any;\n\ttransformStore: any;\n\tjumper: JumpConfig3D;\n\t$jumper: JumpInput3D;\n\tjumperState: JumpState3D;\n}\n\nexport function isJumper3DGrounded(params: {\n\tsupportToi?: number | null;\n\tvelocityY: number;\n\tsnapToGroundDistance?: number;\n}): boolean {\n\tif (params.snapToGroundDistance != null) {\n\t\treturn (\n\t\t\tparams.supportToi != null &&\n\t\t\tparams.supportToi <= params.snapToGroundDistance &&\n\t\t\tparams.velocityY <= 0.25\n\t\t);\n\t}\n\n\treturn (\n\t\tparams.supportToi != null &&\n\t\tparams.velocityY > -2.0 &&\n\t\tparams.velocityY < 2.0\n\t);\n}\n\nfunction shouldSnapJumper3DToGround(\n\tsupport: GroundProbeSupportHit | null,\n\toptions: Jumper3DBehaviorOptions,\n\tvelocityY: number,\n): support is GroundProbeSupportHit {\n\treturn (\n\t\tsupport != null &&\n\t\toptions.snapToGroundDistance != null &&\n\t\tvelocityY <= 0.25 &&\n\t\tsupport.toi <= options.snapToGroundDistance\n\t);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Behavior System adapter\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass Jumper3DBehaviorSystem implements BehaviorSystem {\n\tprivate behavior = new Jumper3DBehavior();\n\tprivate groundProbe: GroundProbe3D;\n\tprivate initializedEntities = new Set<string>();\n\tprivate timeSinceGroundedMs = new Map<string, number>();\n\tprivate wasJumpHeld = new Map<string, boolean>();\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate world: any,\n\t\tprivate scene: any,\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {\n\t\tthis.groundProbe = new GroundProbe3D(world);\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(JUMPER_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst jumperRef = link.ref as any;\n\n\t\t\tconst options = jumperRef.options as Jumper3DBehaviorOptions;\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\t\tconst input = gameEntity.$jumper as JumpInput3D | undefined;\n\t\t\t\tconst jumpPressed = !!(input?.jumpPressed || input?.jumpHeld);\n\t\t\t\tthis.wasmStage.setJumper3DInput(handle, jumpPressed);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!gameEntity.body) continue;\n\n\t\t\t// ── Lazy component init ────────────────────────────────────────\n\t\t\tif (!gameEntity.jumper) {\n\t\t\t\tgameEntity.jumper = createJumpConfig3D(options);\n\t\t\t}\n\t\t\tif (!gameEntity.$jumper) {\n\t\t\t\tgameEntity.$jumper = createJumpInput3D();\n\t\t\t}\n\t\t\tif (!gameEntity.jumperState) {\n\t\t\t\tgameEntity.jumperState = createJumpState3D();\n\t\t\t}\n\n\t\t\tif (!this.initializedEntities.has(gameEntity.uuid)) {\n\t\t\t\tthis.initializedEntities.add(gameEntity.uuid);\n\t\t\t\tgameEntity.body.setGravityScale(0, true);\n\t\t\t}\n\n\t\t\t// ── Lazy FSM init ──────────────────────────────────────────────\n\t\t\tif (!jumperRef.fsm && gameEntity.jumperState) {\n\t\t\t\tjumperRef.fsm = new Jumper3DFSM({\n\t\t\t\t\tstate: gameEntity.jumperState,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// ── Ground detection ───────────────────────────────────────────\n\t\t\tconst rayLength = options.groundRayLength ?? 1.0;\n\t\t\tconst bodyVel = gameEntity.body.linvel();\n\t\t\tconst probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(gameEntity);\n\t\t\tconst support = this.groundProbe.probeSupport(gameEntity, {\n\t\t\t\trayLength,\n\t\t\t\tmode: 'center',\n\t\t\t\tdebug: options.debugGroundProbe ?? false,\n\t\t\t\tscene: this.scene,\n\t\t\t\toriginYOffset: probeOriginYOffset,\n\t\t\t});\n\t\t\tconst isGrounded = isJumper3DGrounded({\n\t\t\t\tsupportToi: support?.toi ?? null,\n\t\t\t\tvelocityY: bodyVel.y,\n\t\t\t\tsnapToGroundDistance: options.snapToGroundDistance,\n\t\t\t});\n\t\t\tif (shouldSnapJumper3DToGround(support, options, bodyVel.y)) {\n\t\t\t\tconst currentPosition = gameEntity.body.translation();\n\t\t\t\tgameEntity.body.setTranslation(\n\t\t\t\t\t{\n\t\t\t\t\t\tx: currentPosition.x,\n\t\t\t\t\t\ty: getGroundSnapTargetY(gameEntity, support),\n\t\t\t\t\t\tz: currentPosition.z,\n\t\t\t\t\t},\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet tsg = this.timeSinceGroundedMs.get(gameEntity.uuid) ?? 0;\n\t\t\tif (isGrounded) {\n\t\t\t\ttsg = 0;\n\t\t\t} else {\n\t\t\t\ttsg += delta * 1000;\n\t\t\t}\n\t\t\tthis.timeSinceGroundedMs.set(gameEntity.uuid, tsg);\n\n\t\t\t// ── Build context ──────────────────────────────────────────────\n\t\t\t// Each behavior owns its own velocity axes. The jumper only\n\t\t\t// reads/writes Y; horizontal axes are left to the movement\n\t\t\t// controller. We read the current Y from the physics body\n\t\t\t// (post-step) so the jumper always sees the real vertical state.\n\t\t\tconst config: JumpConfig3D = gameEntity.jumper;\n\t\t\tconst input: JumpInput3D = gameEntity.$jumper;\n\t\t\tconst state: JumpState3D = gameEntity.jumperState;\n\t\t\tconst prevHeld = this.wasJumpHeld.get(gameEntity.uuid) ?? false;\n\t\t\tconst held = input.jumpHeld === true;\n\n\t\t\t// Input callbacks run after behavior systems in the frame loop.\n\t\t\t// Reconstruct button edges from held-state history so one-frame\n\t\t\t// `pressed`/`released` pulses are not missed by the jumper tick.\n\t\t\tconst effectiveInput: JumpInput3D = {\n\t\t\t\t...input,\n\t\t\t\tjumpPressed: input.jumpPressed || (held && !prevHeld),\n\t\t\t\tjumpReleased: input.jumpReleased || (!held && prevHeld),\n\t\t\t};\n\n\t\t\tconst store = gameEntity.transformStore;\n\n\t\t\tconst ctx: JumpContext3D = {\n\t\t\t\tdt: delta,\n\t\t\t\tup: { x: 0, y: 1, z: 0 },\n\t\t\t\tvelocityY: bodyVel.y,\n\t\t\t\thorizontalVelocity: { x: bodyVel.x, z: bodyVel.z },\n\t\t\t\tisGrounded,\n\t\t\t\ttimeSinceGroundedMs: tsg,\n\t\t\t\tsetVerticalVelocity: (y: number) => {\n\t\t\t\t\tsetVelocityIntent(\n\t\t\t\t\t\tstore,\n\t\t\t\t\t\t'jumper-3d',\n\t\t\t\t\t\t{ y },\n\t\t\t\t\t\t{ mode: 'replace', priority: 20 },\n\t\t\t\t\t);\n\t\t\t\t\tctx.velocityY = y;\n\t\t\t\t},\n\t\t\t\tsetHorizontalVelocity: (x: number, z: number) => {\n\t\t\t\t\tsetVelocityIntent(\n\t\t\t\t\t\tstore,\n\t\t\t\t\t\t'jumper-3d',\n\t\t\t\t\t\t{ x, z },\n\t\t\t\t\t\t{ mode: 'replace', priority: 20 },\n\t\t\t\t\t);\n\t\t\t\t\tctx.horizontalVelocity.x = x;\n\t\t\t\t\tctx.horizontalVelocity.z = z;\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t// ── Tick ───────────────────────────────────────────────────────\n\t\t\tconst result = this.behavior.tick(config, effectiveInput, ctx, state);\n\t\t\tthis.wasJumpHeld.set(gameEntity.uuid, held);\n\n\t\t\t// ── FSM sync ───────────────────────────────────────────────────\n\t\t\tif (jumperRef.fsm) {\n\t\t\t\t(jumperRef.fsm as Jumper3DFSM).applyTickEvent(\n\t\t\t\t\tresult.event,\n\t\t\t\t\tisGrounded,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Jumper3DBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));\n\t\tthis.wasmStage.attachJumper3D(handle, {\n\t\t\tjumpForce,\n\t\t\tmaxJumps: options.maxJumps ?? 1,\n\t\t\tgravity: options.gravity ?? 20,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.groundProbe.destroy();\n\t\tthis.initializedEntities.clear();\n\t\tthis.timeSinceGroundedMs.clear();\n\t\tthis.wasJumpHeld.clear();\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public descriptor\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Jumper3D — composable 3D jump behavior.\n *\n * Provides height-based jumping, multi-jump, coyote time, jump buffering,\n * variable jump height, configurable fall gravity, and optional air control.\n *\n * Designed to compose with any movement controller (e.g. FirstPersonController)\n * — the controller writes X/Z velocity and Jumper3D writes Y velocity.\n *\n * @example\n * ```typescript\n * import { Jumper3D } from \"@zylem/game-lib/behavior\";\n *\n * const jumper = player.use(Jumper3D, {\n * jumpHeight: 2.5,\n * gravity: 20,\n * maxJumps: 2,\n * coyoteTimeMs: 100,\n * jumpBufferMs: 80,\n * variableJump: { enabled: true, cutGravityMultiplier: 3 },\n * fall: { fallGravityMultiplier: 1.5 },\n * });\n *\n * player.onUpdate(({ inputs }) => {\n * player.$jumper.jumpPressed = inputs.p1.buttons.A.pressed;\n * player.$jumper.jumpHeld = inputs.p1.buttons.A.held > 0;\n * player.$jumper.jumpReleased = inputs.p1.buttons.A.released;\n *\n * const state = jumper.getState(); // Grounded | Jumping | Falling\n * });\n * ```\n */\nexport const Jumper3D = defineBehavior<\n\tJumper3DBehaviorOptions,\n\t{\n\t\tgetState: () => Jumper3DState;\n\t\tisJumping: () => boolean;\n\t\tgetJumpsUsed: () => number;\n\t\tgetJumpsRemaining: () => number;\n\t},\n\tJumper3DEntity\n>({\n\tname: 'jumper-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Jumper3DBehaviorSystem(\n\t\t\tctx.world,\n\t\t\tctx.scene,\n\t\t\tctx.wasmStage ?? null,\n\t\t\tctx.getBehaviorLinks,\n\t\t),\n\tcreateHandle: (ref) => ({\n\t\tgetState: () =>\n\t\t\t(ref.fsm as Jumper3DFSM | undefined)?.getState() ??\n\t\t\tJumper3DState.Grounded,\n\t\tisJumping: () =>\n\t\t\t(ref.fsm as Jumper3DFSM | undefined)?.isJumping() ?? false,\n\t\tgetJumpsUsed: () =>\n\t\t\t(ref.fsm as Jumper3DFSM | undefined)?.getJumpsUsed() ?? 0,\n\t\tgetJumpsRemaining: () => {\n\t\t\tconst maxJumps = ref.options.maxJumps ?? 1;\n\t\t\tconst used =\n\t\t\t\t(ref.fsm as Jumper3DFSM | undefined)?.getJumpsUsed() ?? 0;\n\t\t\treturn maxJumps - used;\n\t\t},\n\t}),\n});\n"],"mappings":"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","names":["JumperTickEvent","Jumper3DState","Jumper3DEvent","input"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getEntityFacingAngle2D,
|
|
3
3
|
resolveAim2D
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6C6NXNEW.js";
|
|
5
5
|
import {
|
|
6
6
|
createTopDownMovementInputComponent
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EIWQM6U3.js";
|
|
8
8
|
|
|
9
9
|
// src/lib/coordinators/top-down-shooter.coordinator.ts
|
|
10
10
|
var TopDownShooterCoordinator = class {
|
|
@@ -50,3 +50,4 @@ var TopDownShooterCoordinator = class {
|
|
|
50
50
|
export {
|
|
51
51
|
TopDownShooterCoordinator
|
|
52
52
|
};
|
|
53
|
+
//# sourceMappingURL=chunk-FPTWVCPN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/coordinators/top-down-shooter.coordinator.ts"],"sourcesContent":["import {\n\tcreateTopDownMovementInputComponent,\n\ttype TopDownMovementInputComponent,\n} from '../behaviors/top-down-movement/components';\nimport type {\n\tShooter2DHandle,\n\tShooter2DSourceEntity,\n\tShooter2DStageLike,\n} from '../behaviors/shooter-2d/shooter-2d.descriptor';\nimport { getEntityFacingAngle2D, resolveAim2D } from './shared/top-down-aim';\n\nexport interface TopDownShooterInput {\n\tmoveX: number;\n\tmoveY: number;\n\taimX: number;\n\taimY: number;\n\tshootPressed: boolean;\n\tshootHeld: boolean;\n}\n\ntype TopDownShooterEntity = Shooter2DSourceEntity & {\n\t$topDownMovement?: TopDownMovementInputComponent;\n};\n\nexport class TopDownShooterCoordinator {\n\tconstructor(\n\t\tprivate entity: TopDownShooterEntity,\n\t\tprivate shooter: Shooter2DHandle,\n\t\tprivate stage: Shooter2DStageLike,\n\t) {}\n\n\tpublic update(input: TopDownShooterInput): void {\n\t\tif (!this.entity.$topDownMovement) {\n\t\t\tthis.entity.$topDownMovement = createTopDownMovementInputComponent();\n\t\t}\n\n\t\tthis.entity.$topDownMovement.moveX = input.moveX;\n\t\tthis.entity.$topDownMovement.moveY = input.moveY;\n\t\tthis.entity.$topDownMovement.faceX = input.aimX;\n\t\tthis.entity.$topDownMovement.faceY = input.aimY;\n\n\t\tif (!input.shootPressed && !input.shootHeld) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sourcePosition = this.entity.body?.translation();\n\t\tif (!sourcePosition) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst aim = resolveAim2D(\n\t\t\tinput.aimX,\n\t\t\tinput.aimY,\n\t\t\tgetEntityFacingAngle2D(this.entity),\n\t\t);\n\t\tvoid this.shooter.fire({\n\t\t\tsource: this.entity,\n\t\t\tstage: this.stage,\n\t\t\ttarget: {\n\t\t\t\tx: sourcePosition.x + aim.direction.x,\n\t\t\t\ty: sourcePosition.y + aim.direction.y,\n\t\t\t},\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;;AAwBO,IAAM,4BAAN,MAAgC;AAAA,EACtC,YACS,QACA,SACA,OACP;AAHO;AACA;AACA;AAAA,EACN;AAAA,EAHM;AAAA,EACA;AAAA,EACA;AAAA,EAGF,OAAO,OAAkC;AAC/C,QAAI,CAAC,KAAK,OAAO,kBAAkB;AAClC,WAAK,OAAO,mBAAmB,oCAAoC;AAAA,IACpE;AAEA,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAC3C,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAC3C,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAC3C,SAAK,OAAO,iBAAiB,QAAQ,MAAM;AAE3C,QAAI,CAAC,MAAM,gBAAgB,CAAC,MAAM,WAAW;AAC5C;AAAA,IACD;AAEA,UAAM,iBAAiB,KAAK,OAAO,MAAM,YAAY;AACrD,QAAI,CAAC,gBAAgB;AACpB;AAAA,IACD;AAEA,UAAM,MAAM;AAAA,MACX,MAAM;AAAA,MACN,MAAM;AAAA,MACN,uBAAuB,KAAK,MAAM;AAAA,IACnC;AACA,SAAK,KAAK,QAAQ,KAAK;AAAA,MACtB,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,QAAQ;AAAA,QACP,GAAG,eAAe,IAAI,IAAI,UAAU;AAAA,QACpC,GAAG,eAAe,IAAI,IAAI,UAAU;AAAA,MACrC;AAAA,IACD,CAAC;AAAA,EACF;AACD;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getBounds2DNormalFromHits
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KDY5N6J4.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/coordinators/boundary-ricochet.coordinator.ts
|
|
6
6
|
var BoundaryRicochetCoordinator = class {
|
|
@@ -34,3 +34,4 @@ var BoundaryRicochetCoordinator = class {
|
|
|
34
34
|
export {
|
|
35
35
|
BoundaryRicochetCoordinator
|
|
36
36
|
};
|
|
37
|
+
//# sourceMappingURL=chunk-GCNRXAKH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/coordinators/boundary-ricochet.coordinator.ts"],"sourcesContent":["import { GameEntity } from '../entities/entity';\nimport { Ricochet2DHandle } from '../behaviors/ricochet-2d/ricochet-2d.descriptor';\nimport { WorldBoundary2DHandle } from '../behaviors/world-boundary-2d/world-boundary-2d.descriptor';\nimport { MoveableEntity } from '../actions/capabilities/moveable';\nimport { getBounds2DNormalFromHits } from '../behaviors/shared/bounds-2d';\n\n/**\n * Coordinator that bridges WorldBoundary2DBehavior and Ricochet2DBehavior.\n * \n * Automatically handles:\n * 1. Checking boundary hits\n * 2. Computing collision normals\n * 3. Requesting ricochet result\n * 4. Applying movement\n */\nexport class BoundaryRicochetCoordinator {\n constructor(\n private entity: GameEntity<any> & MoveableEntity,\n private boundary: WorldBoundary2DHandle,\n private ricochet: Ricochet2DHandle\n ) {}\n\n /**\n * Update loop - call this every frame.\n * Applies ricochet via transformStore and notifies listeners.\n * \n * @returns true if ricochet was applied, false otherwise\n */\n public update(): boolean {\n const hits = this.boundary.getLastHits();\n if (!hits) return false;\n\n const anyHit = hits.left || hits.right || hits.top || hits.bottom;\n if (!anyHit) return false;\n\n const normal = getBounds2DNormalFromHits(hits);\n\n // Apply ricochet (also emits to listeners)\n return this.ricochet.applyRicochet({\n entity: this.entity,\n contact: { normal: { x: normal.x, y: normal.y } },\n });\n }\n}\n"],"mappings":";;;;;AAeO,IAAM,8BAAN,MAAkC;AAAA,EACrC,YACY,QACA,UACA,UACV;AAHU;AACA;AACA;AAAA,EACT;AAAA,EAHS;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASL,SAAkB;AACrB,UAAM,OAAO,KAAK,SAAS,YAAY;AACvC,QAAI,CAAC,KAAM,QAAO;AAElB,UAAM,SAAS,KAAK,QAAQ,KAAK,SAAS,KAAK,OAAO,KAAK;AAC3D,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,SAAS,0BAA0B,IAAI;AAG7C,WAAO,KAAK,SAAS,cAAc;AAAA,MAC/B,QAAQ,KAAK;AAAA,MACb,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,GAAG,GAAG,OAAO,EAAE,EAAE;AAAA,IACpD,CAAC;AAAA,EACL;AACJ;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/destructible-prebake/source-geometry.ts","../src/lib/destructible-prebake/cache-key.ts","../src/lib/destructible-prebake/payload.ts"],"sourcesContent":["/**\n * Normalizes source mesh geometry for Voronoi prebake / fracture so runtime and\n * CLI tooling share one code path (float attributes, non-indexed, root-relative transform).\n */\n\nimport {\n\tBufferAttribute,\n\tBufferGeometry,\n\tMatrix4,\n\ttype Group,\n\ttype Mesh,\n} from 'three';\n\ntype ReadableGeometryAttribute = Pick<\n\tBufferAttribute,\n\t'count' | 'itemSize' | 'getComponent'\n>;\n\nfunction cloneAttributeAsFloat32(\n\tattribute: ReadableGeometryAttribute,\n): BufferAttribute {\n\tconst values = new Float32Array(attribute.count * attribute.itemSize);\n\tlet offset = 0;\n\tfor (let index = 0; index < attribute.count; index += 1) {\n\t\tfor (let component = 0; component < attribute.itemSize; component += 1) {\n\t\t\tvalues[offset] = attribute.getComponent(index, component);\n\t\t\toffset += 1;\n\t\t}\n\t}\n\n\treturn new BufferAttribute(values, attribute.itemSize);\n}\n\n/**\n * Clones geometry with float32 attributes and expands indexed meshes to non-indexed.\n */\nexport function normalizeFractureSourceGeometry(\n\tsourceGeometry: BufferGeometry,\n): BufferGeometry {\n\tconst geometry = sourceGeometry.clone();\n\tfor (const [name, attribute] of Object.entries(geometry.attributes)) {\n\t\tgeometry.setAttribute(name, cloneAttributeAsFloat32(attribute));\n\t}\n\n\tconst index = geometry.getIndex();\n\tif (!index) {\n\t\treturn geometry;\n\t}\n\n\tconst indices = new Uint32Array(index.count);\n\tfor (let cursor = 0; cursor < index.count; cursor += 1) {\n\t\tindices[cursor] = index.getX(cursor);\n\t}\n\n\tgeometry.setIndex(new BufferAttribute(indices, 1));\n\treturn geometry.toNonIndexed();\n}\n\n/**\n * Produces fracture-space geometry: normalized mesh vertices in root-local space.\n */\nexport function buildNormalizedFractureSourceGeometry(\n\tmesh: Mesh,\n\troot: Group,\n): BufferGeometry {\n\tconst geometry = normalizeFractureSourceGeometry(mesh.geometry);\n\troot.updateMatrixWorld(true);\n\tmesh.updateMatrixWorld(true);\n\n\tconst relativeMatrix = new Matrix4()\n\t\t.copy(root.matrixWorld)\n\t\t.invert()\n\t\t.multiply(mesh.matrixWorld);\n\n\tgeometry.applyMatrix4(relativeMatrix);\n\tgeometry.computeBoundingBox();\n\tgeometry.computeBoundingSphere();\n\treturn geometry;\n}\n","/**\n * Stable JSON key for matching prebaked fragment templates to fracture options.\n */\n\nimport type { FractureOptions as PinataFractureOptions } from '@dgreenheck/three-pinata';\nimport { Vector2, Vector3 } from 'three';\n\nfunction vector2ToTuple(value?: Vector2): [number, number] | null {\n\tif (!value) {\n\t\treturn null;\n\t}\n\n\treturn [value.x, value.y];\n}\n\nfunction vector3ToTuple(value?: Vector3): [number, number, number] | null {\n\tif (!value) {\n\t\treturn null;\n\t}\n\n\treturn [value.x, value.y, value.z];\n}\n\n/**\n * Serializes fracture options for prebake cache identity (mesh not included).\n */\nexport function buildFractureGeometryCacheKey(\n\toptions: PinataFractureOptions,\n): string {\n\treturn JSON.stringify({\n\t\tfractureMethod: options.fractureMethod,\n\t\tfragmentCount: options.fragmentCount,\n\t\tfracturePlanes: {\n\t\t\tx: options.fracturePlanes?.x ?? true,\n\t\t\ty: options.fracturePlanes?.y ?? true,\n\t\t\tz: options.fracturePlanes?.z ?? true,\n\t\t},\n\t\ttextureScale: vector2ToTuple(options.textureScale),\n\t\ttextureOffset: vector2ToTuple(options.textureOffset),\n\t\tseed: options.seed ?? null,\n\t\tvoronoiOptions: options.voronoiOptions\n\t\t\t? {\n\t\t\t\tmode: options.voronoiOptions.mode,\n\t\t\t\tseedPoints:\n\t\t\t\t\toptions.voronoiOptions.seedPoints?.map((point) => vector3ToTuple(point)),\n\t\t\t\tprojectionAxis: options.voronoiOptions.projectionAxis ?? null,\n\t\t\t\tprojectionNormal: vector3ToTuple(options.voronoiOptions.projectionNormal),\n\t\t\t\tuseApproximation: options.voronoiOptions.useApproximation ?? false,\n\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\toptions.voronoiOptions.approximationNeighborCount ?? 12,\n\t\t\t}\n\t\t\t: null,\n\t});\n}\n","/**\n * Serializable payloads for destructible Voronoi prebake in a Web Worker.\n */\n\nimport { FractureOptions, type DestructibleMesh } from '@dgreenheck/three-pinata';\nimport {\n\tBufferAttribute,\n\tBufferGeometry,\n\tQuaternion,\n\tVector2,\n\tVector3,\n} from 'three';\n\nexport interface PlainBufferGeometryPayload {\n\tattributes: Record<\n\t\tstring,\n\t\t{\n\t\t\tarray: ArrayBuffer;\n\t\t\titemSize: number;\n\t\t\tnormalized?: boolean;\n\t\t}\n\t>;\n}\n\nexport type PlainFractureOptions = {\n\tfractureMethod: 'voronoi' | 'simple';\n\tfragmentCount: number;\n\tfracturePlanes: { x: boolean; y: boolean; z: boolean };\n\ttextureScale: [number, number];\n\ttextureOffset: [number, number];\n\tseed?: number;\n\tvoronoiOptions?: {\n\t\tmode: '3D' | '2.5D';\n\t\tseedPoints?: [number, number, number][];\n\t\timpactPoint?: [number, number, number];\n\t\timpactRadius?: number;\n\t\tprojectionAxis?: 'x' | 'y' | 'z' | 'auto' | null;\n\t\tprojectionNormal?: [number, number, number];\n\t\tuseApproximation: boolean;\n\t\tapproximationNeighborCount: number;\n\t};\n};\n\nexport type PlainWorkerFragmentPayload = {\n\tattributes: PlainBufferGeometryPayload['attributes'];\n\tposition: [number, number, number];\n\tquaternion: [number, number, number, number];\n\tscale: [number, number, number];\n};\n\nexport type PrebakeWorkerRequest = {\n\tgeometry: PlainBufferGeometryPayload;\n\toptions: PlainFractureOptions;\n};\n\nexport type PrebakeWorkerResponse = {\n\tfragments: PlainWorkerFragmentPayload[];\n};\n\nexport interface DestructiblePrebakeWorkerAPI {\n\tprebake(request: PrebakeWorkerRequest): Promise<PrebakeWorkerResponse>;\n}\n\n/**\n * Copies a buffer geometry into detached ArrayBuffers suitable for postMessage transfer.\n */\nexport function bufferGeometryToPlain(geometry: BufferGeometry): {\n\tpayload: PlainBufferGeometryPayload;\n\ttransferables: ArrayBuffer[];\n} {\n\tconst attributes: PlainBufferGeometryPayload['attributes'] = {};\n\tconst transferables: ArrayBuffer[] = [];\n\n\tfor (const name of Object.keys(geometry.attributes)) {\n\t\tconst attr = geometry.getAttribute(name);\n\t\tif (!attr || !(attr instanceof BufferAttribute)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst view = attr.array as ArrayBufferView;\n\t\tconst buffer = view.buffer.slice(\n\t\t\tview.byteOffset,\n\t\t\tview.byteOffset + view.byteLength,\n\t\t);\n\t\ttransferables.push(buffer);\n\t\tattributes[name] = {\n\t\t\tarray: buffer,\n\t\t\titemSize: attr.itemSize,\n\t\t\tnormalized: attr.normalized,\n\t\t};\n\t}\n\n\treturn { payload: { attributes }, transferables };\n}\n\n/**\n * Rebuilds a BufferGeometry from a plain payload (e.g. in a worker).\n */\nexport function plainToBufferGeometry(\n\tpayload: PlainBufferGeometryPayload,\n): BufferGeometry {\n\tconst geometry = new BufferGeometry();\n\n\tfor (const [name, spec] of Object.entries(payload.attributes)) {\n\t\tconst array = new Float32Array(spec.array);\n\t\tgeometry.setAttribute(\n\t\t\tname,\n\t\t\tnew BufferAttribute(array, spec.itemSize, spec.normalized),\n\t\t);\n\t}\n\n\treturn geometry;\n}\n\n/**\n * Serializes {@link FractureOptions} for structured clone / worker transfer.\n */\nexport function pinataFractureOptionsToPlain(\n\toptions: FractureOptions,\n): PlainFractureOptions {\n\tconst voronoi = options.voronoiOptions;\n\treturn {\n\t\tfractureMethod: options.fractureMethod,\n\t\tfragmentCount: options.fragmentCount,\n\t\tfracturePlanes: {\n\t\t\tx: options.fracturePlanes.x,\n\t\t\ty: options.fracturePlanes.y,\n\t\t\tz: options.fracturePlanes.z,\n\t\t},\n\t\ttextureScale: [options.textureScale.x, options.textureScale.y],\n\t\ttextureOffset: [options.textureOffset.x, options.textureOffset.y],\n\t\tseed: options.seed,\n\t\tvoronoiOptions: voronoi\n\t\t\t? {\n\t\t\t\tmode: voronoi.mode,\n\t\t\t\tseedPoints: voronoi.seedPoints?.map((p) => [p.x, p.y, p.z]),\n\t\t\t\timpactPoint: voronoi.impactPoint\n\t\t\t\t\t? [voronoi.impactPoint.x, voronoi.impactPoint.y, voronoi.impactPoint.z]\n\t\t\t\t\t: undefined,\n\t\t\t\timpactRadius: voronoi.impactRadius,\n\t\t\t\tprojectionAxis: voronoi.projectionAxis ?? null,\n\t\t\t\tprojectionNormal: voronoi.projectionNormal\n\t\t\t\t\t? [\n\t\t\t\t\t\tvoronoi.projectionNormal.x,\n\t\t\t\t\t\tvoronoi.projectionNormal.y,\n\t\t\t\t\t\tvoronoi.projectionNormal.z,\n\t\t\t\t\t]\n\t\t\t\t\t: undefined,\n\t\t\t\tuseApproximation: voronoi.useApproximation ?? false,\n\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\tvoronoi.approximationNeighborCount ?? 12,\n\t\t\t}\n\t\t\t: undefined,\n\t};\n}\n\n/**\n * Reconstructs {@link FractureOptions} from a plain payload.\n */\nexport function plainFractureOptionsToPinata(\n\tplain: PlainFractureOptions,\n): FractureOptions {\n\treturn new FractureOptions({\n\t\tfractureMethod: plain.fractureMethod,\n\t\tfragmentCount: plain.fragmentCount,\n\t\tfracturePlanes: plain.fracturePlanes,\n\t\ttextureScale: new Vector2(plain.textureScale[0], plain.textureScale[1]),\n\t\ttextureOffset: new Vector2(plain.textureOffset[0], plain.textureOffset[1]),\n\t\tseed: plain.seed,\n\t\tvoronoiOptions: plain.voronoiOptions\n\t\t\t? {\n\t\t\t\tmode: plain.voronoiOptions.mode,\n\t\t\t\tseedPoints: plain.voronoiOptions.seedPoints?.map(\n\t\t\t\t\t([x, y, z]) => new Vector3(x, y, z),\n\t\t\t\t),\n\t\t\t\timpactPoint: plain.voronoiOptions.impactPoint\n\t\t\t\t\t? new Vector3(\n\t\t\t\t\t\tplain.voronoiOptions.impactPoint[0],\n\t\t\t\t\t\tplain.voronoiOptions.impactPoint[1],\n\t\t\t\t\t\tplain.voronoiOptions.impactPoint[2],\n\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\timpactRadius: plain.voronoiOptions.impactRadius,\n\t\t\t\tprojectionAxis:\n\t\t\t\t\tplain.voronoiOptions.projectionAxis === null\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: plain.voronoiOptions.projectionAxis ?? undefined,\n\t\t\t\tprojectionNormal: plain.voronoiOptions.projectionNormal\n\t\t\t\t\t? new Vector3(\n\t\t\t\t\t\tplain.voronoiOptions.projectionNormal[0],\n\t\t\t\t\t\tplain.voronoiOptions.projectionNormal[1],\n\t\t\t\t\t\tplain.voronoiOptions.projectionNormal[2],\n\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tuseApproximation: plain.voronoiOptions.useApproximation,\n\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\tplain.voronoiOptions.approximationNeighborCount,\n\t\t\t}\n\t\t\t: undefined,\n\t});\n}\n\n/**\n * Converts worker response fragments into template parts for the main-thread cache.\n */\nexport function plainWorkerResultToTemplateParts(response: PrebakeWorkerResponse): Array<{\n\tgeometry: BufferGeometry;\n\tposition: Vector3;\n\tquaternion: Quaternion;\n\tscale: Vector3;\n}> {\n\treturn response.fragments.map((fragment) => {\n\t\tconst geometry = plainToBufferGeometry({ attributes: fragment.attributes });\n\t\tgeometry.computeBoundingBox();\n\t\tgeometry.computeBoundingSphere();\n\t\treturn {\n\t\t\tgeometry,\n\t\t\tposition: new Vector3(\n\t\t\t\tfragment.position[0],\n\t\t\t\tfragment.position[1],\n\t\t\t\tfragment.position[2],\n\t\t\t),\n\t\t\tquaternion: new Quaternion(\n\t\t\t\tfragment.quaternion[0],\n\t\t\t\tfragment.quaternion[1],\n\t\t\t\tfragment.quaternion[2],\n\t\t\t\tfragment.quaternion[3],\n\t\t\t),\n\t\t\tscale: new Vector3(\n\t\t\t\tfragment.scale[0],\n\t\t\t\tfragment.scale[1],\n\t\t\t\tfragment.scale[2],\n\t\t\t),\n\t\t};\n\t});\n}\n\n/**\n * Serializes fracture fragments for Comlink.transfer (used in the worker).\n */\nexport function destructibleFragmentsToPlainResponse(\n\tfragments: readonly DestructibleMesh[],\n): {\n\tresponse: PrebakeWorkerResponse;\n\ttransferables: ArrayBuffer[];\n} {\n\tconst out: PlainWorkerFragmentPayload[] = [];\n\tconst transferables: ArrayBuffer[] = [];\n\n\tfor (const fragment of fragments) {\n\t\tconst { payload, transferables: geoTransfer } = bufferGeometryToPlain(\n\t\t\tfragment.geometry,\n\t\t);\n\t\tfor (const buffer of geoTransfer) {\n\t\t\ttransferables.push(buffer);\n\t\t}\n\t\tout.push({\n\t\t\tattributes: payload.attributes,\n\t\t\tposition: [fragment.position.x, fragment.position.y, fragment.position.z],\n\t\t\tquaternion: [\n\t\t\t\tfragment.quaternion.x,\n\t\t\t\tfragment.quaternion.y,\n\t\t\t\tfragment.quaternion.z,\n\t\t\t\tfragment.quaternion.w,\n\t\t\t],\n\t\t\tscale: [fragment.scale.x, fragment.scale.y, fragment.scale.z],\n\t\t});\n\t\tfragment.geometry.dispose();\n\t}\n\n\treturn { response: { fragments: out }, transferables };\n}\n"],"mappings":"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","names":["BufferAttribute","BufferGeometry"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/behaviors/shared/direction-2d.ts"],"sourcesContent":["export interface Direction2D {\n\tx: number;\n\ty: number;\n}\n\nconst DIRECTION_EPSILON = 1e-6;\n\nexport function normalizeDirection2D(x: number, y: number): Direction2D | null {\n\tconst length = Math.hypot(x, y);\n\tif (length <= DIRECTION_EPSILON) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tx: x / length,\n\t\ty: y / length,\n\t};\n}\n\nexport function angleFromDirection2D(direction: Direction2D): number {\n\treturn Math.atan2(-direction.x, direction.y);\n}\n\nexport function directionFromAngle2D(angle: number): Direction2D {\n\treturn {\n\t\tx: Math.sin(-angle),\n\t\ty: Math.cos(-angle),\n\t};\n}\n\nexport function rightFromAngle2D(angle: number): Direction2D {\n\treturn {\n\t\tx: Math.cos(angle),\n\t\ty: Math.sin(angle),\n\t};\n}\n\nexport function rotateLocalOffset2D(\n\toffset: Direction2D,\n\tangle: number,\n): Direction2D {\n\tconst right = rightFromAngle2D(angle);\n\tconst forward = directionFromAngle2D(angle);\n\treturn {\n\t\tx: right.x * offset.x + forward.x * offset.y,\n\t\ty: right.y * offset.x + forward.y * offset.y,\n\t};\n}\n\nexport function getRotationAngle2D(\n\trotation: { x: number; y: number; z: number; w: number },\n): number {\n\treturn Math.atan2(\n\t\t2 * (rotation.w * rotation.z + rotation.x * rotation.y),\n\t\t1 - 2 * (rotation.y * rotation.y + rotation.z * rotation.z),\n\t);\n}\n"],"mappings":";AAKA,IAAM,oBAAoB;AAEnB,SAAS,qBAAqB,GAAW,GAA+B;AAC9E,QAAM,SAAS,KAAK,MAAM,GAAG,CAAC;AAC9B,MAAI,UAAU,mBAAmB;AAChC,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,GAAG,IAAI;AAAA,IACP,GAAG,IAAI;AAAA,EACR;AACD;AAEO,SAAS,qBAAqB,WAAgC;AACpE,SAAO,KAAK,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;AAC5C;AAEO,SAAS,qBAAqB,OAA4B;AAChE,SAAO;AAAA,IACN,GAAG,KAAK,IAAI,CAAC,KAAK;AAAA,IAClB,GAAG,KAAK,IAAI,CAAC,KAAK;AAAA,EACnB;AACD;AAEO,SAAS,iBAAiB,OAA4B;AAC5D,SAAO;AAAA,IACN,GAAG,KAAK,IAAI,KAAK;AAAA,IACjB,GAAG,KAAK,IAAI,KAAK;AAAA,EAClB;AACD;AAEO,SAAS,oBACf,QACA,OACc;AACd,QAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAM,UAAU,qBAAqB,KAAK;AAC1C,SAAO;AAAA,IACN,GAAG,MAAM,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO;AAAA,IAC3C,GAAG,MAAM,IAAI,OAAO,IAAI,QAAQ,IAAI,OAAO;AAAA,EAC5C;AACD;AAEO,SAAS,mBACf,UACS;AACT,SAAO,KAAK;AAAA,IACX,KAAK,SAAS,IAAI,SAAS,IAAI,SAAS,IAAI,SAAS;AAAA,IACrD,IAAI,KAAK,SAAS,IAAI,SAAS,IAAI,SAAS,IAAI,SAAS;AAAA,EAC1D;AACD;","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 = {}) {
|
|
@@ -549,3 +549,4 @@ export {
|
|
|
549
549
|
Platformer3DBehavior,
|
|
550
550
|
Platformer3DBehavior2
|
|
551
551
|
};
|
|
552
|
+
//# sourceMappingURL=chunk-JAN34G6S.js.map
|