@hology/core 0.0.250 → 0.0.252

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/effects/sequence/sequence-data.d.ts +2 -0
  2. package/dist/effects/sequence/sequence-data.js +1 -1
  3. package/dist/effects/sequence/sequence-definitions.js +1 -1
  4. package/dist/effects/sequence/sequence-player.d.ts +4 -0
  5. package/dist/effects/sequence/sequence-player.js +1 -1
  6. package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
  7. package/dist/effects/vfx/gpu-vfx-world-service.js +1 -1
  8. package/dist/gameplay/actors/actor.js +1 -1
  9. package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
  10. package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
  11. package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
  12. package/dist/gameplay/initiate.d.ts +4 -0
  13. package/dist/gameplay/initiate.js +1 -1
  14. package/dist/gameplay/services/render.d.ts +11 -3
  15. package/dist/gameplay/services/render.js +1 -1
  16. package/dist/rendering/native-dlss-upscaler.d.ts +104 -0
  17. package/dist/rendering/native-dlss-upscaler.js +4 -0
  18. package/dist/rendering/node-material-webgpu-resolver.d.ts +2 -1
  19. package/dist/rendering/node-material-webgpu-resolver.js +1 -1
  20. package/dist/rendering/post-process-effect.d.ts +1 -1
  21. package/dist/rendering/post-process-effect.js +1 -1
  22. package/dist/rendering/rendering-backend.d.ts +9 -0
  23. package/dist/rendering/rendering-backend.js +4 -0
  24. package/dist/rendering/upscaling-pass.d.ts +9 -1
  25. package/dist/rendering/upscaling-pass.js +1 -1
  26. package/dist/rendering/webgl-backend.d.ts +32 -0
  27. package/dist/rendering/webgl-backend.js +4 -0
  28. package/dist/rendering/webgpu-experimental-backend.d.ts +19 -2
  29. package/dist/rendering/webgpu-experimental-backend.js +1 -1
  30. package/dist/rendering/webgpu-runtime-bridge.d.ts +22 -0
  31. package/dist/rendering/webgpu-runtime-bridge.js +4 -0
  32. package/dist/rendering.d.ts +45 -16
  33. package/dist/rendering.js +1 -1
  34. package/dist/scene/asset-resource-loader.d.ts +5 -0
  35. package/dist/scene/asset-resource-loader.js +1 -1
  36. package/dist/scene/materializer.js +1 -1
  37. package/dist/scene/materials/water.js +1 -1
  38. package/dist/scene/runtime-bundled-backend-service.d.ts +7 -0
  39. package/dist/scene/runtime-bundled-backend-service.js +1 -1
  40. package/dist/scene/storage/packed-json.js +1 -1
  41. package/dist/secondary-motion/runtime.d.ts +1 -1
  42. package/dist/secondary-motion/runtime.js +1 -1
  43. package/dist/test/actor-attachment.test.d.ts +2 -0
  44. package/dist/test/actor-attachment.test.js +4 -0
  45. package/dist/test/gpu-sprite-compiler.test.js +1 -1
  46. package/dist/test/native-dlss-upscaler.test.d.ts +2 -0
  47. package/dist/test/native-dlss-upscaler.test.js +4 -0
  48. package/dist/test/node-material-webgpu-resolver.test.js +1 -1
  49. package/dist/test/webgpu-experimental-backend.test.js +1 -1
  50. package/dist/utils/uuid.js +1 -1
  51. package/package.json +1 -1
  52. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
- import{__decorate as e,__metadata as t}from"tslib";import*as s from"three";import{Service as r}from"typedi";import{inject as i}from"../../gameplay/inject.js";import{AssetLoader as n}from"../../gameplay/services/asset-loader.js";import{ViewController as a}from"../../gameplay/services/render.js";import{AssetResourceLoader as o}from"../../scene/asset-resource-loader.js";import{AssetsProvider as l}from"../../scene/assets-provider.js";import{ShaderProvider as h}from"../../gameplay/services/shader-provider.js";import{createGpuSpriteShaderGraphResolver as u}from"./vfx-materializer.js";import{GpuSpriteRenderClassCache as c,hasGpuUnsupportedVfxInputBindings as d}from"./gpu-sprite-compiler.js";import{addGpuSpriteRenderGraphPasses as p}from"./gpu-sprite-render-graph.js";import{GpuSpriteWorldRuntime as m}from"./gpu-sprite-world-runtime.js";import{buildGpuSpriteTemplate as g,GpuSpriteTemplateCache as f}from"./gpu-sprite-template.js";import{gpuVfxCapacityClass as y}from"./gpu-vfx-capacity.js";export class GpuVfxEffectHandle{constructor(e,t){this.epoch=e,this.instance=t,this.released=!1}setPosition(e){return!this.released&&this.epoch.runtime.setPosition(this.instance,e)}setTransform(e){return!this.released&&this.epoch.runtime.setTransform(this.instance,e)}pause(){return!this.released&&this.epoch.runtime.pause(this.instance)}play(){return!this.released&&this.epoch.runtime.play(this.instance)}restart(){return!this.released&&this.epoch.runtime.restart(this.instance)}stop(){return!this.released&&this.epoch.runtime.stop(this.instance)}expire(e){return!this.released&&this.epoch.runtime.stop(this.instance,Math.max(0,e))}kill(){return!this.released&&this.epoch.runtime.stop(this.instance,0)}setTimescale(e){return!this.released&&this.epoch.runtime.setTimescale(this.instance,e)}setInput(e,t){return!this.released&&this.epoch.runtime.setInput(this.instance,e,t)}release(){return!this.released&&(this.released=!0,this.epoch.runtime.destroy(this.instance))}get active(){return!this.released&&this.epoch.runtime.has(this.instance)}}export class PreparedGpuVfxEffect{constructor(e,t,s){this.entry=e,this.spawnEntry=t,this.releaseEntry=s,this.released=!1}spawn(e){return this.released?null:this.spawnEntry(this.entry,e)}release(){this.released||(this.released=!0,this.releaseEntry(this.entry))}}let v=class{constructor(){this.view=i(a),this.assetLoader=i(n),this.assetsProvider=i(l),this.assetResources=i(o),this.shaderProvider=i(h),this.templateCache=new f,this.renderClassCache=new c,this.entriesByAssetId=new Map,this.entries=new Set,this.epochs=new Set,this.reportedCpuFallbacks=new Set,this.cpuFallbackReasons=new Map,this.currentEpoch=null,this.nextGeneration=1,this.rebuildTail=Promise.resolve(!0),this.unregisterRenderGraph=null,this.estimatedWorldBytes=0,this.profilingEnabled=!1,this.view.onLateUpdate().subscribe(e=>this.update(e))}setProfilingEnabled(e){this.profilingEnabled=e}getStats(){const e=this.currentEpoch;return null==e?null:{particles:e.runtime.runtime.getStats(),scheduler:e.runtime.scheduler.getStats()}}beginPipelineWarmup(){const e=[],t=new s.Vector3;for(const s of this.epochs){for(const r of s.templateIndices.values()){const i=s.runtime.spawn(r,t);null!=i&&e.push({epoch:s,instance:i})}s.runtime.flushActivePages()}return()=>{for(const{epoch:t,instance:s}of e)t.runtime.destroy(s);for(const e of this.epochs)e.runtime.flushActivePages()}}async prepare(e,t,s){if(this.cpuFallbackReasons.delete(this.fallbackKey(e,t)),"webgpu-experimental"!==this.view.requestedBackend)return this.reportCpuFallback(e,t,[`GPU VFX requires the WebGPU renderer; the requested renderer is "${this.view.requestedBackend}".`]),null;if(d(e))return this.reportCpuFallback(e,t,["one or more authored VFX input bindings are not supported on GPU"]),null;let r=null==s||0===s.size?this.entriesByAssetId.get(e.id):void 0;if(null==r||r.asset!==e||r.revision!==t){const i=r;r={asset:e,revision:t,pending:(async()=>(null!=i&&await this.retireEntry(i.pending),this.createEntry(e,t,s)))()},null!=s&&0!==s.size||this.entriesByAssetId.set(e.id,r)}const i=await r.pending;if(null==i)return this.reportCpuFallback(e,t,["GPU template preparation rejected this asset without a diagnostic"]),null;i.references+=1;const n=y(i.references),a=this.currentEpoch?.reservations.get(i)??0,o=i.reservedInstances;return n>i.reservedInstances&&(i.reservedInstances=n),a<n&&!await this.queueRebuild()?(i.references-=1,i.reservedInstances=o,this.reportCpuFallback(e,t,["the shared GPU VFX world could not grow within its memory budget or WebGPU device limits"]),null):new PreparedGpuVfxEffect(i,(e,t)=>this.spawn(e,t),e=>this.releaseEntry(e))}getFallbackReasons(e,t){return this.cpuFallbackReasons.get(this.fallbackKey(e,t))??[]}async createEntry(e,t,s){const r={assets:this.assets,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,revision:t,meshInputs:s},i=null==s||0===s.size?await this.templateCache.resolve(e,r):await g(e,r);if(null==i.template){const s=i.compatibility.issues.filter(e=>"error"===e.severity).map(e=>`${e.emitter}: ${e.message}`);return this.reportCpuFallback(e,t,s.length>0?s:i.reasons),null}const n={asset:e,revision:t,references:0,reservedInstances:1,retired:!1,runtimeMeshInput:null!=s&&s.size>0,template:i.template};return this.entries.add(n),n}spawn(e,t){let s=this.currentEpoch,r=s?.templateIndices.get(e);if(null==r&&e.retired)for(const t of this.epochs){const i=t.templateIndices.get(e);t.disposalQueued||null==i||(s=t,r=i)}if(null==s||null==r)return null;const i=s.runtime.spawn(r,t);return null==i?null:new GpuVfxEffectHandle(s,i)}releaseEntry(e){e.references=Math.max(0,e.references-1),!e.runtimeMeshInput||e.references>0||e.retired||(e.retired=!0,this.entries.delete(e),this.queueRebuild())}async retireEntry(e){const t=await e;null!=t&&(t.retired=!0,this.entries.delete(t))}queueRebuild(){const e=this.rebuildTail.then(()=>this.rebuildWorld()).catch(e=>(console.error("[Hology GPU VFX] Failed to rebuild the shared world generation.",e),!1));return this.rebuildTail=e,e}async rebuildWorld(){const e=[...this.entries].filter(e=>!e.retired);if(0===e.length)return null!=this.currentEpoch&&(this.currentEpoch.retired=!0,this.currentEpoch=null,this.disposeRetiredEpochs()),!0;if(null!=this.currentEpoch&&this.currentEpoch.templateIndices.size===e.length&&e.every(e=>(this.currentEpoch.reservations.get(e)??0)>=e.reservedInstances))return!0;const t=[...this.epochs].reduce((e,t)=>t===this.currentEpoch&&0===t.runtime.scheduler.getStats().activeInstances?e:e+t.estimatedBytes,0),s=Math.max(0,this.view.webgpuVfxWorldMemoryBudgetBytes-t),r=await m.create({templates:e.map(e=>({asset:e.asset,revision:e.revision,maximumInstances:e.reservedInstances,preparedTemplate:e.template})),assets:this.assets,templateCache:this.templateCache,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,particlePageSize:256,aliveCountReadback:this.profilingEnabled,device:this.view.experimentalWebGpuDevice??void 0,maximumStorageBytes:s});if(null==r)return!1;const i=r.runtime.getStats().storageBytes;if(i>this.view.webgpuVfxWorldMemoryBudgetBytes||t+i>this.view.webgpuVfxWorldMemoryBudgetBytes)return r.dispose(),console.warn(`[Hology GPU VFX] Refusing shared world growth: retained storage would become ${w(t+i)} MiB, exceeding the ${w(this.view.webgpuVfxWorldMemoryBudgetBytes)} MiB budget.`),!1;const n={generation:this.nextGeneration++,runtime:r,templateIndices:new Map(e.map((e,t)=>[e,t])),reservations:new Map(e.map(e=>[e,e.reservedInstances])),estimatedBytes:i,retired:!1,disposalQueued:!1};return null!=this.currentEpoch&&(this.currentEpoch.retired=!0),this.currentEpoch=n,this.epochs.add(n),this.estimatedWorldBytes+=i,this.ensureRenderGraph(),console.info(`[Hology GPU VFX] Shared world generation ${n.generation}: ${e.length} template(s), ${e.reduce((e,t)=>e+t.reservedInstances,0)} reserved instance(s), ${r.runtime.emitters.length} emitter slots, ${r.runtime.getStats().capacity.toLocaleString()} particle slots, ${w(i)} MiB estimated storage.`),this.disposeRetiredEpochs(),!0}ensureRenderGraph(){if(null!=this.unregisterRenderGraph)return;const e=(e,t)=>p(e,this,t,"WorldGpuVfx");e.getSceneTextureReads=()=>this.getSceneTextureReads(),this.unregisterRenderGraph=this.view.registerExperimentalWebGpuRenderGraphExtension(e)}update(e){for(const t of this.epochs)t.runtime.update(e);this.disposeRetiredEpochs()}disposeRetiredEpochs(){for(const e of this.epochs){if(!e.retired||e.disposalQueued||0!==e.runtime.scheduler.getStats().activeInstances||[...e.templateIndices.keys()].some(e=>e.retired&&e.references>0))continue;e.disposalQueued=!0,this.epochs.delete(e),this.estimatedWorldBytes=Math.max(0,this.estimatedWorldBytes-e.estimatedBytes);const t=()=>{e.runtime.dispose(),console.info(`[Hology GPU VFX] Retired shared world generation ${e.generation}, releasing ${w(e.estimatedBytes)} MiB estimated storage.`)},s=this.view.experimentalWebGpuDevice;null==s?t():s.queue.onSubmittedWorkDone().then(t,t)}}reportCpuFallback(e,t,s){const r=this.fallbackKey(e,t);this.cpuFallbackReasons.set(r,[...s]),this.reportedCpuFallbacks.has(r)||(this.reportedCpuFallbacks.add(r),console.warn(`[Hology GPU VFX] Falling back to CPU for "${e.name}".`,s))}fallbackKey(e,t){return`${e.id}:${t??""}`}executeCompute(e){for(const t of this.epochs)t.runtime.runtime.executeCompute(e)}executeRender(e,t){for(const s of this.epochs)s.runtime.runtime.executeRender(e,t)}getSceneTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getSceneTextureReads())e.add(s);return[...e]}getComputeTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getComputeTextureReads())e.add(s);return[...e]}get assets(){return{getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMesh:async e=>(await this.assetResources.getMesh(await this.assetsProvider.getAsset(e),{applyMaterials:!0,rescale:!0})).scene}}get resolveCustomMaterial(){return u(this.assetsProvider,this.assetResources,this.shaderProvider,{getAsset:e=>this.assetLoader.getAsset(e),getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMaterial:e=>this.assetLoader.getMaterialByAssetId(e),getMesh:e=>this.assetLoader.getModelByAssetId(e).then(e=>e.scene)})}};v=e([r(),t("design:paramtypes",[])],v);export{v as GpuVfxWorldService};function w(e){return(e/1048576).toFixed(1)}/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import*as s from"three";import{Service as r}from"typedi";import{inject as i}from"../../gameplay/inject.js";import{AssetLoader as n}from"../../gameplay/services/asset-loader.js";import{ViewController as a}from"../../gameplay/services/render.js";import{AssetResourceLoader as o}from"../../scene/asset-resource-loader.js";import{AssetsProvider as l}from"../../scene/assets-provider.js";import{ShaderProvider as h}from"../../gameplay/services/shader-provider.js";import{ensureWebGpuRuntimeBindings as u}from"../../rendering/webgpu-runtime-bridge.js";import{createGpuSpriteShaderGraphResolver as c}from"./vfx-materializer.js";import{GpuSpriteRenderClassCache as d,hasGpuUnsupportedVfxInputBindings as p}from"./gpu-sprite-compiler.js";import{addGpuSpriteRenderGraphPasses as m}from"./gpu-sprite-render-graph.js";import{GpuSpriteWorldRuntime as g}from"./gpu-sprite-world-runtime.js";import{buildGpuSpriteTemplate as f,GpuSpriteTemplateCache as y}from"./gpu-sprite-template.js";import{gpuVfxCapacityClass as v}from"./gpu-vfx-capacity.js";export class GpuVfxEffectHandle{constructor(e,t){this.epoch=e,this.instance=t,this.released=!1}setPosition(e){return!this.released&&this.epoch.runtime.setPosition(this.instance,e)}setTransform(e){return!this.released&&this.epoch.runtime.setTransform(this.instance,e)}pause(){return!this.released&&this.epoch.runtime.pause(this.instance)}play(){return!this.released&&this.epoch.runtime.play(this.instance)}restart(){return!this.released&&this.epoch.runtime.restart(this.instance)}stop(){return!this.released&&this.epoch.runtime.stop(this.instance)}expire(e){return!this.released&&this.epoch.runtime.stop(this.instance,Math.max(0,e))}kill(){return!this.released&&this.epoch.runtime.stop(this.instance,0)}setTimescale(e){return!this.released&&this.epoch.runtime.setTimescale(this.instance,e)}setInput(e,t){return!this.released&&this.epoch.runtime.setInput(this.instance,e,t)}release(){return!this.released&&(this.released=!0,this.epoch.runtime.destroy(this.instance))}get active(){return!this.released&&this.epoch.runtime.has(this.instance)}}export class PreparedGpuVfxEffect{constructor(e,t,s){this.entry=e,this.spawnEntry=t,this.releaseEntry=s,this.released=!1}spawn(e){return this.released?null:this.spawnEntry(this.entry,e)}release(){this.released||(this.released=!0,this.releaseEntry(this.entry))}}let w=class{constructor(){this.view=i(a),this.assetLoader=i(n),this.assetsProvider=i(l),this.assetResources=i(o),this.shaderProvider=i(h),this.templateCache=new y,this.renderClassCache=new d,this.entriesByAssetId=new Map,this.entries=new Set,this.epochs=new Set,this.reportedCpuFallbacks=new Set,this.cpuFallbackReasons=new Map,this.currentEpoch=null,this.nextGeneration=1,this.rebuildTail=Promise.resolve(!0),this.unregisterRenderGraph=null,this.estimatedWorldBytes=0,this.profilingEnabled=!1,this.view.onLateUpdate().subscribe(e=>this.update(e))}setProfilingEnabled(e){this.profilingEnabled=e}getStats(){const e=this.currentEpoch;return null==e?null:{particles:e.runtime.runtime.getStats(),scheduler:e.runtime.scheduler.getStats()}}beginPipelineWarmup(){const e=[],t=new s.Vector3;for(const s of this.epochs){for(const r of s.templateIndices.values()){const i=s.runtime.spawn(r,t);null!=i&&e.push({epoch:s,instance:i})}s.runtime.flushActivePages()}return()=>{for(const{epoch:t,instance:s}of e)t.runtime.destroy(s);for(const e of this.epochs)e.runtime.flushActivePages()}}async prepare(e,t,s){if(this.cpuFallbackReasons.delete(this.fallbackKey(e,t)),"webgpu"!==this.view.requestedBackend)return this.reportCpuFallback(e,t,[`GPU VFX requires the WebGPU renderer; the requested renderer is "${this.view.requestedBackend}".`]),null;if(await u(),p(e))return this.reportCpuFallback(e,t,["one or more authored VFX input bindings are not supported on GPU"]),null;let r=null==s||0===s.size?this.entriesByAssetId.get(e.id):void 0;if(null==r||r.asset!==e||r.revision!==t){const i=r;r={asset:e,revision:t,pending:(async()=>(null!=i&&await this.retireEntry(i.pending),this.createEntry(e,t,s)))()},null!=s&&0!==s.size||this.entriesByAssetId.set(e.id,r)}const i=await r.pending;if(null==i)return this.reportCpuFallback(e,t,["GPU template preparation rejected this asset without a diagnostic"]),null;i.references+=1;const n=v(i.references),a=this.currentEpoch?.reservations.get(i)??0,o=i.reservedInstances;return n>i.reservedInstances&&(i.reservedInstances=n),a<n&&!await this.queueRebuild()?(i.references-=1,i.reservedInstances=o,this.reportCpuFallback(e,t,["the shared GPU VFX world could not grow within its memory budget or WebGPU device limits"]),null):new PreparedGpuVfxEffect(i,(e,t)=>this.spawn(e,t),e=>this.releaseEntry(e))}getFallbackReasons(e,t){return this.cpuFallbackReasons.get(this.fallbackKey(e,t))??[]}async createEntry(e,t,s){const r={assets:this.assets,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,revision:t,meshInputs:s},i=null==s||0===s.size?await this.templateCache.resolve(e,r):await f(e,r);if(null==i.template){const s=i.compatibility.issues.filter(e=>"error"===e.severity).map(e=>`${e.emitter}: ${e.message}`);return this.reportCpuFallback(e,t,s.length>0?s:i.reasons),null}const n={asset:e,revision:t,references:0,reservedInstances:1,retired:!1,runtimeMeshInput:null!=s&&s.size>0,template:i.template};return this.entries.add(n),n}spawn(e,t){let s=this.currentEpoch,r=s?.templateIndices.get(e);if(null==r&&e.retired)for(const t of this.epochs){const i=t.templateIndices.get(e);t.disposalQueued||null==i||(s=t,r=i)}if(null==s||null==r)return null;const i=s.runtime.spawn(r,t);return null==i?null:new GpuVfxEffectHandle(s,i)}releaseEntry(e){e.references=Math.max(0,e.references-1),!e.runtimeMeshInput||e.references>0||e.retired||(e.retired=!0,this.entries.delete(e),this.queueRebuild())}async retireEntry(e){const t=await e;null!=t&&(t.retired=!0,this.entries.delete(t))}queueRebuild(){const e=this.rebuildTail.then(()=>this.rebuildWorld()).catch(e=>(console.error("[Hology GPU VFX] Failed to rebuild the shared world generation.",e),!1));return this.rebuildTail=e,e}async rebuildWorld(){const e=[...this.entries].filter(e=>!e.retired);if(0===e.length)return null!=this.currentEpoch&&(this.currentEpoch.retired=!0,this.currentEpoch=null,this.disposeRetiredEpochs()),!0;if(null!=this.currentEpoch&&this.currentEpoch.templateIndices.size===e.length&&e.every(e=>(this.currentEpoch.reservations.get(e)??0)>=e.reservedInstances))return!0;const t=[...this.epochs].reduce((e,t)=>t===this.currentEpoch&&0===t.runtime.scheduler.getStats().activeInstances?e:e+t.estimatedBytes,0),s=Math.max(0,this.view.webgpuVfxWorldMemoryBudgetBytes-t),r=await g.create({templates:e.map(e=>({asset:e.asset,revision:e.revision,maximumInstances:e.reservedInstances,preparedTemplate:e.template})),assets:this.assets,templateCache:this.templateCache,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,particlePageSize:256,aliveCountReadback:this.profilingEnabled,device:this.view.experimentalWebGpuDevice??void 0,maximumStorageBytes:s});if(null==r)return!1;const i=r.runtime.getStats().storageBytes;if(i>this.view.webgpuVfxWorldMemoryBudgetBytes||t+i>this.view.webgpuVfxWorldMemoryBudgetBytes)return r.dispose(),console.warn(`[Hology GPU VFX] Refusing shared world growth: retained storage would become ${b(t+i)} MiB, exceeding the ${b(this.view.webgpuVfxWorldMemoryBudgetBytes)} MiB budget.`),!1;const n={generation:this.nextGeneration++,runtime:r,templateIndices:new Map(e.map((e,t)=>[e,t])),reservations:new Map(e.map(e=>[e,e.reservedInstances])),estimatedBytes:i,retired:!1,disposalQueued:!1};return null!=this.currentEpoch&&(this.currentEpoch.retired=!0),this.currentEpoch=n,this.epochs.add(n),this.estimatedWorldBytes+=i,this.ensureRenderGraph(),console.info(`[Hology GPU VFX] Shared world generation ${n.generation}: ${e.length} template(s), ${e.reduce((e,t)=>e+t.reservedInstances,0)} reserved instance(s), ${r.runtime.emitters.length} emitter slots, ${r.runtime.getStats().capacity.toLocaleString()} particle slots, ${b(i)} MiB estimated storage.`),this.disposeRetiredEpochs(),!0}ensureRenderGraph(){if(null!=this.unregisterRenderGraph)return;const e=(e,t)=>m(e,this,t,"WorldGpuVfx");e.getSceneTextureReads=()=>this.getSceneTextureReads(),this.unregisterRenderGraph=this.view.registerExperimentalWebGpuRenderGraphExtension(e)}update(e){for(const t of this.epochs)t.runtime.update(e);this.disposeRetiredEpochs()}disposeRetiredEpochs(){for(const e of this.epochs){if(!e.retired||e.disposalQueued||0!==e.runtime.scheduler.getStats().activeInstances||[...e.templateIndices.keys()].some(e=>e.retired&&e.references>0))continue;e.disposalQueued=!0,this.epochs.delete(e),this.estimatedWorldBytes=Math.max(0,this.estimatedWorldBytes-e.estimatedBytes);const t=()=>{e.runtime.dispose(),console.info(`[Hology GPU VFX] Retired shared world generation ${e.generation}, releasing ${b(e.estimatedBytes)} MiB estimated storage.`)},s=this.view.experimentalWebGpuDevice;null==s?t():s.queue.onSubmittedWorkDone().then(t,t)}}reportCpuFallback(e,t,s){const r=this.fallbackKey(e,t);this.cpuFallbackReasons.set(r,[...s]),this.reportedCpuFallbacks.has(r)||(this.reportedCpuFallbacks.add(r),console.warn(`[Hology GPU VFX] Falling back to CPU for "${e.name}".`,s))}fallbackKey(e,t){return`${e.id}:${t??""}`}executeCompute(e){for(const t of this.epochs)t.runtime.runtime.executeCompute(e)}executeRender(e,t){for(const s of this.epochs)s.runtime.runtime.executeRender(e,t)}getSceneTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getSceneTextureReads())e.add(s);return[...e]}getComputeTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getComputeTextureReads())e.add(s);return[...e]}get assets(){return{getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMesh:async e=>(await this.assetResources.getMesh(await this.assetsProvider.getAsset(e),{applyMaterials:!0,rescale:!0})).scene}}get resolveCustomMaterial(){return c(this.assetsProvider,this.assetResources,this.shaderProvider,{getAsset:e=>this.assetLoader.getAsset(e),getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMaterial:e=>this.assetLoader.getMaterialByAssetId(e),getMesh:e=>this.assetLoader.getModelByAssetId(e).then(e=>e.scene)})}};w=e([r(),t("design:paramtypes",[])],w);export{w as GpuVfxWorldService};function b(e){return(e/1048576).toFixed(1)}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{__decorate as t,__metadata as e}from"tslib";import o,{ignore as i}from"@plumier/reflect";import{Subject as s,skipWhile as r}from"rxjs";import{Group as n}from"three";import a,{Service as p}from"typedi";import{ActorComponent as c}from"./component.js";import{initComponentsSync as d}from"./internal/component-init.js";import{activeContainerInstance as m,containerRefMap as l}from"./internal/container-map.js";import{randomString as h}from"../../utils/math.js";import{inject as u}from"../inject.js";import{ViewController as f}from"../services/render.js";import{actorConstructContext as y}from"./factory.js";import{NetRole as j}from"../net/service/net-actor-role.js";import{registerActorClass as g}from"./type-registry.js";export{getActorClassById,getActorClassId,getRegisteredActorClasses}from"./type-registry.js";export const $actorOptions=Symbol("actor-options");export function getActorOptions(t){return t[$actorOptions]??b}const b={replicate:!1};export function Actor(t=b){const e=p({transient:!0});return function(i){const s=arguments[1],r=t.typeId??s?.name??i.name,n=g(r,i);null!=n&&n!==i&&console.warn(`Duplicate actor class name ${r}`),i.__actorId=r,i.__isActor=!0,e(i),o.noop()(i),o.parameterProperties()(i),i[$actorOptions]=t}}let U=0;export class BaseActor{get position(){return this.object?.position}get quaternion(){return this.object?.quaternion}get rotation(){return this.object?.rotation}onInit(){}onBeginPlay(){}onEndPlay(){}applySceneParameters(t,e){return!1}onUpdate(t){}onLateUpdate(t){}constructor(){this.id=++U,this.netRole=j.authority,this.__isInitialised=!1,this.object=new n,this.disposed=new s,this.attachedComponents=[],y.actor=this,this.onUpdate!==BaseActor.prototype.onUpdate&&u(f).onUpdate(this).pipe(r(()=>!this.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==BaseActor.prototype.onLateUpdate&&u(f).onLateUpdate(this).pipe(r(()=>!this.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}attach(t,e){const o=m.value,i=l.get(this)??m.value??a.of("default");m.value=i;const s=h();i.set({id:s,type:t,transient:!0});const r=i.get(s);if(m.value=o,null!=e)for(const t of Object.keys(e))r[t]=e[t];return this.__isInitialised&&(r.actor=this,r.onInit(),d(r,this)),this.attachedComponents.push(r),r}getComponent(t){for(const e of Object.values(this))if(e instanceof t)return e;for(const e of this.attachedComponents)if(e instanceof t)return e}}t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"position",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"quaternion",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"rotation",null);export function _setupActorUpdateEventHandlers(){this.onUpdate!==c.prototype.onUpdate&&u(f).onUpdate(this.actor).pipe(r(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==c.prototype.onLateUpdate&&u(f).onLateUpdate(this.actor).pipe(r(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}/*
1
+ import{__decorate as t,__metadata as e}from"tslib";import o,{ignore as i}from"@plumier/reflect";import{Subject as r,skipWhile as s}from"rxjs";import{Group as n}from"three";import a,{Service as p}from"typedi";import{ActorComponent as c}from"./component.js";import{initComponentsSync as d}from"./internal/component-init.js";import{activeContainerInstance as l,containerRefMap as m}from"./internal/container-map.js";import{randomString as h}from"../../utils/math.js";import{inject as u}from"../inject.js";import{ViewController as f}from"../services/render.js";import{actorConstructContext as y}from"./factory.js";import{NetRole as j}from"../net/service/net-actor-role.js";import{registerActorClass as g}from"./type-registry.js";export{getActorClassById,getActorClassId,getRegisteredActorClasses}from"./type-registry.js";export const $actorOptions=Symbol("actor-options");export function getActorOptions(t){return t[$actorOptions]??b}const b={replicate:!1};export function Actor(t=b){const e=p({transient:!0});return function(i){const r=arguments[1],s=t.typeId??r?.name??i.name,n=g(s,i);null!=n&&n!==i&&console.warn(`Duplicate actor class name ${s}`),i.__actorId=s,i.__isActor=!0,e(i),o.noop()(i),o.parameterProperties()(i),i[$actorOptions]=t}}let U=0;export class BaseActor{get position(){return this.object?.position}get quaternion(){return this.object?.quaternion}get rotation(){return this.object?.rotation}onInit(){}onBeginPlay(){}onEndPlay(){}applySceneParameters(t,e){return!1}onUpdate(t){}onLateUpdate(t){}constructor(){this.id=++U,this.netRole=j.authority,this.__isInitialised=!1,this.object=new n,this.disposed=new r,this.attachedComponents=[],y.actor=this,this.onUpdate!==BaseActor.prototype.onUpdate&&u(f).onUpdate(this).pipe(s(()=>!this.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==BaseActor.prototype.onLateUpdate&&u(f).onLateUpdate(this).pipe(s(()=>!this.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}attach(t,e){const o=l.value,i=m.get(this)??l.value??a.of("default"),r=h(),s=y.actor;let n;try{l.value=i,y.actor=this,i.set({id:r,type:t,transient:!0}),n=i.get(r)}finally{y.actor=s,l.value=o}if(n.actor=this,null!=e)for(const t of Object.keys(e))n[t]=e[t];return this.__isInitialised&&(n.onInit(),d(n,this)),this.attachedComponents.push(n),n}getComponent(t){for(const e of Object.values(this))if(e instanceof t)return e;for(const e of this.attachedComponents)if(e instanceof t)return e}}t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"position",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"quaternion",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"rotation",null);export function _setupActorUpdateEventHandlers(){this.onUpdate!==c.prototype.onUpdate&&u(f).onUpdate(this.actor).pipe(s(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==c.prototype.onLateUpdate&&u(f).onLateUpdate(this.actor).pipe(s(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{__decorate as t}from"tslib";import{ActorComponent as e,Component as o}from"../../../component.js";import{canCrossFadeFromAnimationAction as i}from"../../../../animation/animation-action.js";import{RootMotionClip as s}from"../../../../animation/root-motion.js";import{inject as r}from"../../../../inject.js";import{ViewController as n}from"../../../../services/render.js";import{AnimationMixer as l,Bone as a,Object3D as h,LoopOnce as c,Raycaster as d,Vector3 as p,SkinnedMesh as u,Skeleton as f,Quaternion as g,Matrix4 as m,MathUtils as y,ArrowHelper as k,Group as S}from"three";import{getCharacterMovementLike as w}from"./character-movement-like.js";import{CCDIKSolver as b}from"three/addons/animation/CCDIKSolver.js";import{World as v}from"../../../../services/world.js";import{PhysicsSystem as L,RayTestResult as x}from"../../../../services/physics/physics-system.js";import{ArrayMap as I}from"../../../../../utils/collections.js";import{getAnimationClipRigId as B,getAnimationRigChainBoneNames as P,getAnimationRigDataFromObject as R,getAnimationRigIdFromObject as F,setAnimationClipRigId as D}from"../../../../animation/retarget.js";const A=new p(0,-1,0),M=new p(0,1,0),W=new p(1,1,1),T=new g,C=new p,O=new p,q=new p,V=new p,U=new p,E=new g,N=new g,H=new g,z=new g,j=new m,Q=new m,G=new p(1,0,0),_=new p(0,1,0),$=new p(0,0,1);function K(){return{point:new p,normal:new p,hasNormal:!1}}const Y=["mixamorigHips","Hips","hips","Pelvis","pelvis"],J={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},X={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},Z=["left","right"];let tt=class extends e{constructor(){super(...arguments),this.viewController=r(n),this.poseProcessors=new I,this.stateMachines=[],this.upperStateMachines=[],this.fadeTime=.2,this.movementSpeed=null,this.upperBodyTimer=0,this.upperBodyOverride=!1,this.fullBodyTimer=0,this.currentFullBodyPriority=-1,this.currentUpperBodyPriority=-1,this.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.externalControlActive=!1,this.world=r(v),this.physicsSystem=r(L),this._footIkEnabled=!1,this.footIkMoving=!1,this.footIkRayStartHeight=.5,this.footIkRayLength=1.5,this.footIkRaycastMode="physics",this.footIkFootOffset=.08,this.footIkAutoContactOffset=!1,this.footIkPositionLerpSpeed=28,this.footIkRotationLerpSpeed=14,this.footIkWeightInSpeed=34,this.footIkWeightOutSpeed=30,this.footIkMaxSlopeAngleDeg=40,this.footIkForwardSampleDistance=.14,this.footIkSideSampleDistance=.08,this.footIkMaxHorizontalOffset=.22,this.footIkMaxVerticalOffsetDown=.75,this.footIkMaxVerticalOffsetUp=.2,this.footIkPelvisEnabled=!0,this.footIkPelvisBone="mixamorigHips",this.footIkPelvisLerpSpeed=24,this.footIkPelvisMaxOffsetDown=.4,this.footIkPelvisMaxOffsetUp=.08,this.footIkRequireGrounded=!0,this.footIkSimpleTiltOnly=!1,this.footIkDebug=!1,this.footIkDebugNormalLength=.25,this.footIkDebugAxisLength=.2,this.footIkExtraClearance=.01,this.footIkPlantReleaseUpSpeed=.08,this.footIkPlantReleaseExtension=.9,this.footIkPlantAttachExtension=.96,this.footIkPlantReleaseLift=.055,this.footIkPlantAttachLift=.02,this.leftLegIkBones={upperLeg:"mixamorigLeftUpLeg",lowerLeg:"mixamorigLeftLeg",foot:"mixamorigLeftFoot"},this.rightLegIkBones={upperLeg:"mixamorigRightUpLeg",lowerLeg:"mixamorigRightLeg",foot:"mixamorigRightFoot"},this.ikPelvisOffsetY=0,this.ikPelvisDescendantStack=[],this.ikWorldUpdateNodes=[],this.footIkStateReset=!0,this.ikLegState={left:{targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1},right:{targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1}},this.ikWarnedMissingBones=!1,this.raycaster=new d,this.raycastIntersections=[],this.footIkRayTo=new p,this.footIkRayTestResult=new x,this.footIkRayTestOptions={debug:!1,excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:K(),toe:K(),heel:K(),side:K()},this.footIkAxesScratch={up:new p,forward:new p,right:new p},this.footIkSampleAxesScratch={forward:new p,right:new p},this.footIkScratch={footWorldPos:new p,centerRayStart:new p,toeRayStart:new p,heelRayStart:new p,sideRayStart:new p,desiredTargetPos:new p,desiredNormal:new p,desiredForward:new p,debugRayEndA:new p,debugRayEndB:new p,debugRayEndC:new p,debugRayEndD:new p,debugRayEndE:new p,debugRayEndF:new p},this.ikPreSolve={left:{upper:new g,lower:new g,foot:new g},right:{upper:new g,lower:new g,foot:new g}},this.getFullBodyClip=st(t=>t.uuid,t=>et(this.fullBodyMask,t)),this.getUpperBodyClip=st(t=>t.uuid,t=>et(this.upperBodyMask,t))}get footIkEnabled(){return this._footIkEnabled}set footIkEnabled(t){this._footIkEnabled!==t&&(this._footIkEnabled=t,null!=this.ikRoot&&(this.disposeFootIkDebug(),this.initializeFootIk(this.ikRoot,this.ikRootBone),this.syncFootIkDebug()))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=w(this.actor),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,A),this.raycaster.near=0,this.raycaster.far=e,this.raycastIntersections.length=0,this.raycaster.intersectObject(i,!0,this.raycastIntersections);for(const t of this.raycastIntersections)if(!(this.isFootIkDebugObject(t.object)||this.isRelatedToActorHierarchy(t.object)||this.isSkinnedMeshObject(t.object)))return o.point.copy(t.point),null!=t.face?(o.normal.copy(t.face.normal).transformDirection(t.object.matrixWorld).normalize(),o.hasNormal=!0):o.hasNormal=!1,this.raycastIntersections.length=0,!0;return this.raycastIntersections.length=0,!1}rayTestDown(t,e,o){const i=this.footIkRayTo.copy(t).addScaledVector(A,e),s=this.physicsSystem.rayTest(t,i,this.footIkRayTestResult,this.footIkRayTestOptions);return!!s.hasHit&&(o.point.copy(s.hitPoint),o.normal.copy(s.hitNormal),o.normal.lengthSq()>1e-8?(o.normal.normalize(),o.hasNormal=!0):o.hasNormal=!1,!0)}isRelatedToActorHierarchy(t){const e=this.actor?.object;return null!=e&&null!=t&&(nt(t,e)||nt(e,t))}isFootIkDebugObject(t){let e=t;for(;null!=e;){if(!0===e.userData?.footIkDebug)return!0;e=e.parent}return!1}isSkinnedMeshObject(t){let e=t;for(;null!=e;){if(e instanceof u||!0===e.isSkinnedMesh)return!0;e=e.parent}return!1}getRootMotionAction(){if(this.fullBodyAction.getClip()instanceof s)return this.fullBodyAction}getFullBodyAction(){return this.fullBodyAction}setup(t,e,o){null!=e&&(this.upperBodyMask=ot(e),this.fullBodyMask=function(t,e){const o=new Set(ot(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof a||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(rt(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new l(t),this.animationRigId=F(t),this.animationRigData=R(t),this.ikRoot=t,this.ikRootBone=o,this.disposeFootIkDebug(),this.initializeFootIk(t,o),this.syncFootIkDebug()}updateStateMachines(t){this.stateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o&&this.play(o,{priority:e.current.options.priority??0,loop:e.current.options.loop??!0})}),this.upperStateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o?this.playUpper(o,{priority:e.current.options.priority??0,loop:e.current.options.loop??!0}):this.play(this.fullBodyClip)})}addPoseProcessor(t){const e={id:t.id,phase:t.phase??"afterMixer",order:t.order??0,update:t.update};this.removePoseProcessor(e.id);const o=this.poseProcessors.get(e.phase);let i=o.findIndex(t=>t.order>e.order);return-1===i&&(i=o.length),o.splice(i,0,e),()=>{const t=o.indexOf(e);-1!==t&&(o.splice(t,1),0===o.length&&this.poseProcessors.delete(e.phase))}}removePoseProcessor(t){for(const[e,o]of this.poseProcessors.entries()){const i=o.findIndex(e=>e.id===t);if(-1!==i)return o.splice(i,1),void(0===o.length&&this.poseProcessors.delete(e))}}runPoseProcessors(t,e){if(0===this.poseProcessors.size||null==this.mixer||!this.poseProcessors.present(t))return;const o=this.mixer.getRoot();if(!(o instanceof h))return;const i=this.poseProcessorContext??(this.poseProcessorContext={deltaTime:e,phase:t,animation:this,mixer:this.mixer,root:o});i.deltaTime=e,i.phase=t,i.mixer=this.mixer,i.root=o;const s=this.poseProcessors.get(t);for(let t=0;t<s.length;t++)s[t].update(i)}updateInternal(t){if(null==this.mixer)return;if(this.externalControlActive)return;this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1);let e=!1;this.sequenceAnimationReleasePending&&(this.sequenceAnimationReleaseFrames>0?(e=!0,this.sequenceAnimationReleaseFrames--):(this.sequenceAnimationReleasePending=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationControlled=!1,this.overrideFadeTime=null,this.fullBodyTimer=0)),this.upperBodyAction&&this.upperBodyOverride&&this.upperBodyAction.getClip().duration-2*(this.overrideFadeTimeUpper??this.fadeTime)<this.upperBodyTimer&&(this.upperBodyOverride=!1,null!=this.fullBodyClip&&this.transition(this.upperBodyAction,this.getUpperBodyClip(this.fullBodyClip)),this.upperBodyAction=null,this.overrideFadeTimeUpper=null),!this.sequenceAnimationControlled&&!this.sequenceAnimationReleasePending&&this.fullBodyAction&&this.fullBodyAction.loop===c&&this.fullBodyAction.getClip().duration-2*(this.overrideFadeTime??this.fadeTime)<this.fullBodyTimer&&(this.currentFullBodyPriority=-1,this.overrideFadeTime=null),null!=this.characterMovement&&(this.movementSpeed=this.characterMovement.horizontalSpeed),e||this.updateStateMachines(t),this.syncMovementSpeed(this.fullBodyAction),this.upperBodyOverride||this.syncMovementSpeed(this.upperBodyAction),this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t)}initializeFootIk(t,e){if(this.ikSolver=null,this.ikSkinnedMesh=null,this.ikBoneRefs=null,this.ikLegLengths=null,this.ikPelvisBone=null,this.ikPelvisOffsetY=0,this.ikFootAxes=null,this.ikTargetBones=null,this.ikWorldUpdateNodes.length=0,this.footIkStateReset=!0,this.ikWarnedMissingBones=!1,this.ikLegState.left.weight=0,this.ikLegState.right.weight=0,!this.footIkEnabled)return;const o=this.findFirstSkinnedMesh(t);if(null==o||null==o.skeleton)return;this.ikSkinnedMesh=o,t.updateWorldMatrix(!0,!0);const i=o.skeleton,s=P(this.animationRigData,"leftLeg"),r=P(this.animationRigData,"rightLeg"),n=this.resolveLegBoneRefs(i,this.leftLegIkBones,J,s),l=this.resolveLegBoneRefs(i,this.rightLegIkBones,X,r);if(null==n||null==l)return void(this.ikWarnedMissingBones||(this.ikWarnedMissingBones=!0,console.warn(`[CharacterAnimationComponent] Foot IK disabled: missing leg bones. Left=${this.leftLegIkBones.upperLeg}/${this.leftLegIkBones.lowerLeg}/${this.leftLegIkBones.foot}, Right=${this.rightLegIkBones.upperLeg}/${this.rightLegIkBones.lowerLeg}/${this.rightLegIkBones.foot}`)));this.ikBoneRefs={left:n,right:l},this.ikLegLengths={left:this.computeLegLengths(n),right:this.computeLegLengths(l)},this.ikFootAxes={left:this.detectFootAxisBasis(n.foot),right:this.detectFootAxisBasis(l.foot)};const h=this.animationRigData?.bones.find(t=>t.id===this.animationRigData?.pelvisBoneId)?.name;this.ikPelvisBone=this.resolvePelvisBone(i,n,l,h),this.rebuildFootIkWorldUpdateNodes(),this.ikLegState.left.targetPosition.copy(n.foot.getWorldPosition(C)),this.ikLegState.right.targetPosition.copy(l.foot.getWorldPosition(C)),this.ikLegState.left.normal.set(0,1,0),this.ikLegState.right.normal.set(0,1,0),this.ikLegState.left.pitch=0,this.ikLegState.right.pitch=0,this.ikLegState.left.contactOffset=this.estimateFootContactOffset(i,"left",n.foot),this.ikLegState.right.contactOffset=this.estimateFootContactOffset(i,"right",l.foot),this.ikLegState.left.planted=!1,this.ikLegState.right.planted=!1,this.ikLegState.left.lastFootWorldPos.copy(n.foot.getWorldPosition(C)),this.ikLegState.right.lastFootWorldPos.copy(l.foot.getWorldPosition(C)),this.ikLegState.left.hasLastFootSample=!1,this.ikLegState.right.hasLastFootSample=!1;const c=this.resolveFootAxes("left",n.foot),d=this.resolveFootAxes("right",l.foot);this.ikLegState.left.forward.copy(c.forward),this.ikLegState.right.forward.copy(d.forward);const p=e??rt(t);if(null==p)return;let u=i.getBoneByName("_IKTargetLeftFoot"),g=i.getBoneByName("_IKTargetRightFoot"),y=!1;if(null==u&&(u=new a,u.name="_IKTargetLeftFoot",p.add(u),y=!0),null==g&&(g=new a,g.name="_IKTargetRightFoot",p.add(g),y=!0),this.setBoneWorldPosition(u,n.foot.getWorldPosition(C)),this.setBoneWorldPosition(g,l.foot.getWorldPosition(C)),y||i.bones.indexOf(u)<0||i.bones.indexOf(g)<0){const e=i.bones.slice(),o=i.boneInverses.map(t=>t.clone());e.indexOf(u)<0&&(e.push(u),o.push((new m).copy(u.matrixWorld).invert())),e.indexOf(g)<0&&(e.push(g),o.push((new m).copy(g.matrixWorld).invert()));const s=new f(e,o);t.traverse(t=>{const e=t;!0===e.isSkinnedMesh&&e.skeleton===i&&e.bind(s,e.bindMatrix)})}this.ikTargetBones={left:u,right:g},this.rebuildFootIkWorldUpdateNodes();const k=o.skeleton.bones,S={target:k.indexOf(u),effector:k.indexOf(n.foot),links:[{index:k.indexOf(n.lower)},{index:k.indexOf(n.upper)}],iteration:8},w={target:k.indexOf(g),effector:k.indexOf(l.foot),links:[{index:k.indexOf(l.lower)},{index:k.indexOf(l.upper)}],iteration:8};if(S.target<0||S.effector<0||S.links.some(t=>t.index<0)||w.target<0||w.effector<0||w.links.some(t=>t.index<0))return console.warn("[CharacterAnimationComponent] Foot IK disabled: failed to resolve IK indexes in skeleton."),void(this.ikSolver=null);this.ikSolver=new b(o,[S,w])}findFirstSkinnedMesh(t){let e;return t.traverse(t=>{null==e&&(t instanceof u||!0===t.isSkinnedMesh)&&(e=t)}),e}resolveLegBoneRefs(t,e,o,i=[]){const s=this.findBoneByNames(t,[i[0],e.upperLeg,...o.upper].filter(t=>null!=t)),r=this.findBoneByNames(t,[i.at(-2),e.lowerLeg,...o.lower].filter(t=>null!=t)),n=this.findBoneByNames(t,[i.at(-1),e.foot,...o.foot].filter(t=>null!=t));if(null!=s&&null!=r&&null!=n)return{upper:s,lower:r,foot:n}}findBoneByNames(t,e){for(const o of e){const e=t.getBoneByName(o);if(null!=e)return e}}resolvePelvisBone(t,e,o,i){const s=this.findBoneByNames(t,[i,this.footIkPelvisBone,...Y].filter(t=>null!=t));if(null!=s)return s;const r=e.upper.parent,n=o.upper.parent;return null!=r&&r===n&&(r instanceof a||!0===r.isBone)||null!=r&&(r instanceof a||!0===r.isBone)?r:void 0}computeLegLengths(t){const e=t.upper.getWorldPosition(C),o=t.lower.getWorldPosition(O),i=t.foot.getWorldPosition(q),s=e.distanceTo(o),r=o.distanceTo(i);return{upper:s,lower:r,total:s+r}}setBoneWorldPosition(t,e){const o=t.parent;null==o?t.position.copy(e):t.position.copy(C.copy(e).applyMatrix4(j.copy(o.matrixWorld).invert())),t.quaternion.copy(T),t.scale.copy(W),t.updateMatrixWorld(!0)}syncFootIkDebug(){this.footIkDebug&&null!=this.ikRoot?(null!=this.ikDebugRoot&&null!=this.ikDebugLegs||(this.ikDebugRoot=new S,this.ikDebugRoot.name="FootIKDebug",this.ikDebugRoot.userData.footIkDebug=!0,this.ikDebugLegs={left:this.createDebugLeg("LeftFootIK",53503),right:this.createDebugLeg("RightFootIK",16755200)},this.ikDebugRoot.add(this.ikDebugLegs.left.root,this.ikDebugLegs.right.root),this.world.scene.add(this.ikDebugRoot)),this.ikDebugRoot.visible=!0):null!=this.ikDebugRoot&&(this.ikDebugRoot.visible=!1)}disposeFootIkDebug(){null!=this.ikDebugRoot&&(this.ikDebugRoot.removeFromParent(),this.ikDebugRoot.clear()),this.ikDebugRoot=null,this.ikDebugLegs=null}createDebugLeg(t,e){const o=new S;o.name=t,o.userData.footIkDebug=!0;const i=this.createDebugArrow(e),s=this.createDebugArrow(e),r=this.createDebugArrow(e),n=this.createDebugArrow(e),l=this.createDebugArrow(65280),a=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,l,a,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:l,footUp:a,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new k(M,new p,.001,t);return e.userData.footIkDebug=!0,e.traverse(t=>{t.userData.footIkDebug=!0,t.raycast=()=>{}}),e.visible=!1,e}setDebugArrow(t,e,o){C.subVectors(o,e);const i=C.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(C.multiplyScalar(1/i)),t.setLength(i,Math.min(.08,.25*i),Math.min(.05,.2*i)))}resetDebugVisibility(){null!=this.ikDebugLegs&&(this.ikDebugLegs.left.rayCenter.visible=!1,this.ikDebugLegs.left.rayToe.visible=!1,this.ikDebugLegs.left.rayHeel.visible=!1,this.ikDebugLegs.left.raySide.visible=!1,this.ikDebugLegs.left.hitNormal.visible=!1,this.ikDebugLegs.left.footUp.visible=!1,this.ikDebugLegs.left.footToTarget.visible=!1,this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.rayCenter.visible=!1,this.ikDebugLegs.right.rayToe.visible=!1,this.ikDebugLegs.right.rayHeel.visible=!1,this.ikDebugLegs.right.raySide.visible=!1,this.ikDebugLegs.right.hitNormal.visible=!1,this.ikDebugLegs.right.footUp.visible=!1,this.ikDebugLegs.right.footToTarget.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1)}updateFootIk(t){if(this.syncFootIkDebug(),!this.footIkEnabled||null==this.ikBoneRefs||null==this.ikRoot)return void this.resetDebugVisibility();if(!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.footIkStateReset||(this.syncFootIkWorldMatrices(),this.resetFootIkState(),this.footIkStateReset=!0),void this.resetDebugVisibility();this.syncFootIkWorldMatrices(),this.footIkStateReset=!1;const e=this.characterMovement?.isGrounded??!0;return this.footIkSimpleTiltOnly?(this.updatePelvisOffset(t,!1),this.updateLegTiltSimple("left",this.ikBoneRefs.left.foot,this.ikLegState.left,e,t),void this.updateLegTiltSimple("right",this.ikBoneRefs.right.foot,this.ikLegState.right,e,t)):null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver?(this.updatePelvisOffset(t,!1),void this.resetDebugVisibility()):(this.updateLegIkTarget("left",this.ikBoneRefs.left,this.ikLegLengths.left,this.ikTargetBones.left,this.ikLegState.left,e,t),this.updateLegIkTarget("right",this.ikBoneRefs.right,this.ikLegLengths.right,this.ikTargetBones.right,this.ikLegState.right,e,t),this.updatePelvisOffset(t,!0),this.setBoneWorldPosition(this.ikTargetBones.left,this.ikLegState.left.targetPosition),this.setBoneWorldPosition(this.ikTargetBones.right,this.ikLegState.right.targetPosition),this.ikPreSolve.left.upper.copy(this.ikBoneRefs.left.upper.quaternion),this.ikPreSolve.left.lower.copy(this.ikBoneRefs.left.lower.quaternion),this.ikPreSolve.left.foot.copy(this.ikBoneRefs.left.foot.quaternion),this.ikPreSolve.right.upper.copy(this.ikBoneRefs.right.upper.quaternion),this.ikPreSolve.right.lower.copy(this.ikBoneRefs.right.lower.quaternion),this.ikPreSolve.right.foot.copy(this.ikBoneRefs.right.foot.quaternion),null!=this.ikDebugLegs&&(this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1),this.ikSolver.update(),this.blendLegAfterSolve(this.ikBoneRefs.left,this.ikPreSolve.left,this.ikLegState.left.weight),this.blendLegAfterSolve(this.ikBoneRefs.right,this.ikPreSolve.right,this.ikLegState.right.weight),this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),void this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right))}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of Z){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=C.setFromMatrixPosition(e.foot.matrixWorld);o.targetPosition.copy(i),o.lastFootWorldPos.copy(i),o.hasLastFootSample=!0,o.weight=0,o.normal.set(0,1,0);const s=this.resolveFootAxes(t,e.foot,this.footIkAxesScratch);o.forward.copy(s.forward),o.pitch=0,this.footIkAutoContactOffset?o.contactOffset=Math.max(o.contactOffset,this.footIkFootOffset+this.footIkExtraClearance):o.contactOffset=this.footIkFootOffset+this.footIkExtraClearance,o.planted=!1}this.ikPelvisOffsetY=0}}updatePelvisOffset(t,e){if(null==this.ikPelvisBone)return;let o=0;if(e&&this.footIkPelvisEnabled&&null!=this.ikBoneRefs&&null!=this.ikLegLengths){this.ikLegState.left.top=!1,this.ikLegState.right.top=!1;for(const t of Z){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=C.setFromMatrixPosition(e.upper.matrixWorld),n=.998*i.total,l=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(l>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-l)}o=y.clamp(o,-this.footIkPelvisMaxOffsetDown,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=y.lerp(this.ikPelvisOffsetY,o,i);const s=O.setFromMatrixPosition(this.ikPelvisBone.matrixWorld),r=q.copy(s).addScaledVector(M,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(r.applyMatrix4(j.copy(this.ikPelvisBone.parent.matrixWorld).invert())),this.updatePelvisWorldTranslation(s)}updatePelvisWorldTranslation(t){const e=this.ikPelvisBone;if(null==e)return;e.updateMatrix(),null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix),e.matrixWorldNeedsUpdate=!1;const o=e.matrixWorld.elements,i=o[12]-t.x,s=o[13]-t.y,r=o[14]-t.z;if(0===i&&0===s&&0===r)return;const n=this.ikPelvisDescendantStack;n.length=0;for(let t=0;t<e.children.length;t++)n.push(e.children[t]);for(;n.length>0;){const t=n.pop(),e=t.matrixWorld.elements;e[12]+=i,e[13]+=s,e[14]+=r,t.matrixWorldNeedsUpdate=!1;for(let e=0;e<t.children.length;e++)n.push(t.children[e])}}rebuildFootIkWorldUpdateNodes(){const t=this.ikRoot,e=this.ikBoneRefs;if(null==t||null==e)return void(this.ikWorldUpdateNodes.length=0);const o=new Set,i=[this.ikPelvisBone,e.left.upper,e.left.lower,e.left.foot,e.right.upper,e.right.lower,e.right.foot,this.ikTargetBones?.left,this.ikTargetBones?.right];for(const e of i){let i=e;for(;null!=i&&(o.add(i),i!==t);)i=i.parent??void 0}this.ikWorldUpdateNodes.length=0,t.traverse(t=>{o.has(t)&&this.ikWorldUpdateNodes.push(t)})}syncFootIkWorldMatrices(){const t=this.ikRoot;if(null!=t){t.updateWorldMatrix(!0,!1);for(const e of this.ikWorldUpdateNodes)e!==t&&(e.matrixAutoUpdate&&e.updateMatrix(),e.matrixWorldAutoUpdate&&(null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix)),e.matrixWorldNeedsUpdate=!1)}}computeFootVerticalSpeed(t,e,o){return!t.hasLastFootSample||o<=1e-6?0:(e.y-t.lastFootWorldPos.y)/o}updateFootSample(t,e){t.lastFootWorldPos.copy(e),t.hasLastFootSample=!0}estimateFootContactOffset(t,e,o){const i=this.footIkFootOffset+this.footIkExtraClearance;if(!this.footIkAutoContactOffset)return i;const s=t.bones.indexOf(o);if(s<0)return i;const r=t.boneInverses[s];if(null==r)return i;const n=this.ikFootAxes?.[e]??this.detectFootAxisBasis(o),l=o.getWorldPosition(O),h=q.copy(n.upLocal).applyQuaternion(this.getCurrentWorldQuaternion(o,E)).normalize();let c=0;return o.traverse(e=>{if(!(e instanceof a)||e===o)return;const i=t.bones.indexOf(e);if(i<0)return;const s=j.copy(t.boneInverses[i]).invert(),n=Q.copy(r).multiply(s),d=C.setFromMatrixPosition(n),p=V.copy(d).applyMatrix4(o.matrixWorld).sub(l);c=Math.min(c,p.dot(h))}),Math.max(i,-c+this.footIkExtraClearance)}shouldPlantFoot(t,e,o,i,s,r){if(!e||!o)return!1;const n=this.footIkPlantReleaseExtension,l=this.footIkPlantAttachExtension,a=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>a)):s>=l&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=C.setFromMatrixPosition(t.upper.matrixWorld),i=O.setFromMatrixPosition(t.foot.matrixWorld),s=o.distanceTo(i);return e.total<=1e-6?1:y.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=V.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(M),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const l=Math.sqrt(n),a=r-l,h=r+l;return a>=0?a:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,l=r.footWorldPos.setFromMatrixPosition(e.matrixWorld),a=this.computeFootVerticalSpeed(o,l,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(l).addScaledVector(M,this.footIkRayStartHeight),p=r.toeRayStart.copy(d).addScaledVector(c.forward,this.footIkForwardSampleDistance),u=r.heelRayStart.copy(d).addScaledVector(c.forward,-this.footIkForwardSampleDistance),f=r.sideRayStart.copy(d).addScaledVector(c.right,this.footIkSideSampleDistance),g=this.getFirstGroundHit(d,n.center),m=this.getFirstGroundHit(p,n.toe),k=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),w=r.desiredNormal.set(0,1,0),b=r.desiredForward.copy(c.forward);let v=0,L=0,x=this.footIkWeightOutSpeed;const I=null!=g||null!=m||null!=k;let B=l.y;null!=g?B=g.point.y:null!=m&&null!=k?B=.5*(m.point.y+k.point.y):null!=m?B=m.point.y:null!=k&&(B=k.point.y);const P=this.ikBoneRefs?.[t],R=this.ikLegLengths?.[t],F=null!=P&&null!=R?this.computeLegExtensionRatio(P,R):1,D=Math.max(0,l.y-B,l.y-o.targetPosition.y),A=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,I,a,F,D);A?this.computeDesiredGroundNormal(c,g,m,k,S,w)&&(this.computeDesiredFootForward(c.forward,c.right,w,m,k,b),v=this.computeDesiredPitchAngle(m,k,c.forward),L=1,x=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,w,null,null,b);const W=1-Math.exp(-this.footIkPositionLerpSpeed*s),T=1-Math.exp(-x*s);o.normal.lerp(w,W).normalize(),o.forward.lerp(b,W).normalize(),o.pitch=y.lerp(o.pitch,v,W),o.weight=y.lerp(o.weight,L,T),o.planted=A&&L>.001,this.updateFootSample(o,l),this.applySimpleFootPitch(t,e,o),this.updateLegDebug(t,{footWorldPos:l,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:m,heelHit:k,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const l=this.footIkScratch,a=this.footIkHits,h=e.foot,c=l.footWorldPos.setFromMatrixPosition(h.matrixWorld),d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=l.centerRayStart.copy(c).addScaledVector(M,this.footIkRayStartHeight),g=l.toeRayStart.copy(f).addScaledVector(u.forward,this.footIkForwardSampleDistance),m=l.heelRayStart.copy(f).addScaledVector(u.forward,-this.footIkForwardSampleDistance),k=l.sideRayStart.copy(f).addScaledVector(u.right,this.footIkSideSampleDistance),S=this.getFirstGroundHit(f,a.center),w=this.getFirstGroundHit(g,a.toe),b=this.getFirstGroundHit(m,a.heel),v=this.getFirstGroundHit(k,a.side),L=l.desiredTargetPos.copy(c),x=l.desiredNormal.set(0,1,0),I=l.desiredForward.copy(u.forward);let B=0,P=0,R=this.footIkWeightOutSpeed;const F=null!=S||null!=w||null!=b;let D=c.y;null!=S?D=S.point.y:null!=w&&null!=b?D=.5*(w.point.y+b.point.y):null!=w?D=w.point.y:null!=b&&(D=b.point.y);const A=this.computeLegExtensionRatio(e,o),W=Math.max(0,c.y-D,c.y-s.targetPosition.y),T=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,F,d,A,W);if(T){if(L.copy(c),this.computeDesiredGroundNormal(u,S,w,b,v,x)){this.computeDesiredFootForward(u.forward,u.right,x,w,b,I),B=this.computeDesiredPitchAngle(w,b,u.forward);const t=Math.max(0,Math.sin(B))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);L.y=D+e+t,s.top&&(L.y-=this.ikPelvisOffsetY/2),P=1,R=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,x,null,null,I),L.copy(c),L.y+=this.footIkFootOffset;this.clampDesiredFootTarget(e,o,c,L);const C=1-Math.exp(-this.footIkPositionLerpSpeed*n),O=1-Math.exp(-R*n);s.targetPosition.lerp(L,C),s.normal.lerp(x,C).normalize(),s.forward.lerp(I,C).normalize(),s.pitch=y.lerp(s.pitch,B,C),s.weight=y.lerp(s.weight,P,O),s.planted=T&&P>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.updateLegDebug(t,{footWorldPos:c,centerRayStart:f,toeRayStart:g,heelRayStart:m,sideRayStart:k,centerHit:S,toeHit:w,heelHit:b,sideHit:v,desiredNormal:x,desiredTargetPos:s.targetPosition,weight:s.weight})}updateLegDebug(t,e){if(!this.footIkDebug||null==this.ikDebugLegs||null==this.ikBoneRefs)return;const o=this.ikDebugLegs[t],i=this.ikBoneRefs[t],s=this.resolveFootAxes(t,i.foot,this.footIkAxesScratch),r=this.footIkScratch,n=e.centerHit?.point??r.debugRayEndA.copy(e.centerRayStart).addScaledVector(A,this.footIkRayLength),l=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(A,this.footIkRayLength),a=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(A,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(A,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,l),this.setDebugArrow(o.rayHeel,e.heelRayStart,a),this.setDebugArrow(o.raySide,e.sideRayStart,h);const c=e.centerHit?.point??e.toeHit?.point??e.heelHit?.point??e.sideHit?.point??e.footWorldPos;this.setDebugArrow(o.hitNormal,c,r.debugRayEndE.copy(c).addScaledVector(e.desiredNormal,this.footIkDebugNormalLength)),this.setDebugArrow(o.footUp,e.footWorldPos,r.debugRayEndF.copy(e.footWorldPos).addScaledVector(s.up,this.footIkDebugAxisLength*(.15+e.weight))),this.setDebugArrow(o.footToTarget,e.footWorldPos,e.desiredTargetPos)}getFirstGroundHit(t,e){return"physics"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)?e:null:"physicsThenRender"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)||this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null:this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null}resolveGroundSampleAxes(t,e,o,i){const s=o??this.resolveFootAxes(t,e),r=i??{forward:new p,right:new p},n=this.getCurrentWorldDirection(this.actor.object,V);n.addScaledVector(M,-n.dot(M)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(M,-s.forward.dot(M)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const l=U.crossVectors(M,n);return l.lengthSq()<1e-8?l.copy(s.right):l.normalize(),l.dot(s.right)<0&&l.multiplyScalar(-1),r.forward.copy(n),r.right.copy(l),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,V);let l=!1,a=0,h=0;if(null!=o&&null!=i){const e=O.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(a=(o.point.y-i.point.y)/e,l=!0)}if(null!=s&&null!=e){const o=q.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,l=!0)}if(l&&(r.copy(M),r.addScaledVector(t.forward,-a),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():l=!1),l)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),l=!0}return r.dot(M)<0&&r.multiplyScalar(-1),this.clampSlopeNormal(r),!0}computeAverageHitNormal(t,e,o,i,s){s.set(0,0,0);let r=0;return null!=t&&t.hasNormal&&(s.add(t.normal),r++),null!=e&&e.hasNormal&&(s.add(e.normal),r++),null!=o&&o.hasNormal&&(s.add(o.normal),r++),null!=i&&i.hasNormal&&(s.add(i.normal),r++),0===r||s.lengthSq()<1e-8?null:(s.multiplyScalar(1/r).normalize(),s)}computeDesiredFootForward(t,e,o,i,s,r){null!=i&&null!=s?r.subVectors(i.point,s.point):r.copy(t),r.addScaledVector(o,-r.dot(o)),r.lengthSq()<1e-8&&(r.copy(this.getCurrentWorldDirection(this.actor.object,V)),r.addScaledVector(o,-r.dot(o))),r.lengthSq()<1e-8&&r.crossVectors(o,e),r.lengthSq()<1e-8&&r.set(0,0,1),r.normalize();const n=V.copy(this.getCurrentWorldDirection(this.actor.object,V));n.addScaledVector(o,-n.dot(o)),n.lengthSq()<1e-8&&(n.copy(t),n.addScaledVector(o,-n.dot(o))),n.lengthSq()>1e-8&&n.normalize(),r.dot(n)<0&&r.multiplyScalar(-1)}computeDesiredPitchAngle(t,e,o){if(null==t||null==e)return 0;const i=O.subVectors(t.point,e.point),s=Math.abs(i.dot(o));if(s<1e-5)return 0;const r=t.point.y-e.point.y,n=y.degToRad(this.footIkMaxSlopeAngleDeg);return y.clamp(-Math.atan2(r,s),-n,n)}applySimpleFootPitch(t,e,o){if(null==e.parent||o.weight<=.001)return;const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o.pitch*o.weight;if(Math.abs(s)<=1e-5)return;const r=this.resolveLocalPitchSign(i),n=E.copy(e.quaternion),l=N.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(l))}resolveLocalPitchSign(t){const e=H.setFromAxisAngle(t.rightLocal,.15);return q.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=O.subVectors(i,o),r=s.dot(M),n=q.copy(s).addScaledVector(M,-r),l=n.length();l>this.footIkMaxHorizontalOffset&&l>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/l);const a=y.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(M,a),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(C).clone(),c=O.subVectors(i,h),d=c.length(),p=.995*e.total;d>p&&d>1e-6&&i.copy(h).addScaledVector(c,p/d)}solveTwoBoneLeg(t,e,o){const i=e.upper.getWorldPosition(C).clone(),s=e.lower.getWorldPosition(O).clone(),r=e.foot.getWorldPosition(q).clone(),n=i.distanceTo(s),l=s.distanceTo(r);if(n<1e-5||l<1e-5)return;const a=(new p).subVectors(o,i),h=a.length();if(h<1e-5)return;const c=Math.abs(n-l)+1e-4,d=n+l-1e-4,u=y.clamp(h,c,d),f=a.multiplyScalar(1/h),g=(new p).subVectors(s,i).normalize(),m=(new p).subVectors(r,s).normalize(),k=(new p).crossVectors(g,m);k.lengthSq()<1e-8&&(k.copy(this.getCurrentWorldDirection(this.actor.object,C).cross(M)),k.lengthSq()<1e-8&&k.set(1,0,0)),k.normalize();const S=(u*u+n*n-l*l)/(2*u),w=Math.max(n*n-S*S,0),b=Math.sqrt(w),v=(new p).copy(i).addScaledVector(f,S);let L=(new p).crossVectors(k,f);L.lengthSq()<1e-8&&(L=(new p).crossVectors(f,M),L.lengthSq()<1e-8&&(L=new p(1,0,0))),L.normalize();const x=(new p).copy(v).addScaledVector(L,b),I=(new p).copy(v).addScaledVector(L,-b),B=(new p).subVectors(s,v).dot(L)>=0?x:I;this.rotateBoneToward(e.upper,i,s,B),e.upper.updateMatrixWorld(!0);const P=e.lower.getWorldPosition(O),R=e.foot.getWorldPosition(q);this.rotateBoneToward(e.lower,P,R,o),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,i,B,o)}updateSolveDebug(t,e,o,i){if(!this.footIkDebug||null==this.ikDebugLegs)return;const s=this.ikDebugLegs[t];this.setDebugArrow(s.solveUpper,e,o),this.setDebugArrow(s.solveLower,o,i)}rotateBoneToward(t,e,o,i){const s=(new p).subVectors(o,e),r=(new p).subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>.9999)return;const n=(new g).setFromUnitVectors(s,r),l=this.getCurrentWorldQuaternion(t,E),a=N.copy(n).multiply(l);if(null==t.parent)return void t.quaternion.copy(a);const h=this.getCurrentWorldQuaternion(t.parent,H),c=z.copy(h).invert().multiply(a);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=this.getCurrentWorldQuaternion(t,E),o=this.getCurrentWorldDirection(this.actor.object,C);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:G.clone(),world:G.clone().applyQuaternion(e)},{local:_.clone(),world:_.clone().applyQuaternion(e)},{local:$.clone(),world:$.clone().applyQuaternion(e)}];i.push({local:G.clone().multiplyScalar(-1),world:G.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:_.clone().multiplyScalar(-1),world:_.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:$.clone().multiplyScalar(-1),world:$.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(M);e>r&&(r=e,s=t)}let n=i[0],l=-1/0;for(const t of i){if(Math.abs(t.world.dot(s.world))>.6)continue;const e=Math.abs(t.world.dot(o));e>l&&(l=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const a=s.local.clone().normalize(),h=n.local.clone().normalize(),c=a.clone().cross(h).normalize();return{upLocal:a,forwardLocal:c.clone().cross(a).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new p,forward:new p,right:new p},r=this.getCurrentWorldQuaternion(e,E);return s.up.copy(i.upLocal).applyQuaternion(r).normalize(),s.forward.copy(i.forwardLocal).applyQuaternion(r).normalize(),s.right.copy(i.rightLocal).applyQuaternion(r).normalize(),s}getCurrentWorldQuaternion(t,e){return t.matrixWorld.decompose(U,e,V),e}getCurrentWorldDirection(t,e){const o=t.matrixWorld.elements;return e.set(o[8],o[9],o[10]).normalize()}clampSlopeNormal(t){const e=y.clamp(t.dot(M),-1,1),o=Math.acos(e),i=y.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(M,t,s).normalize()}blendLegAfterSolve(t,e,o){if(!(o>=.999)){if(o<=.001)return t.upper.quaternion.copy(e.upper),t.lower.quaternion.copy(e.lower),void t.foot.quaternion.copy(e.foot);this.blendBoneQuaternion(t.upper,e.upper,o),this.blendBoneQuaternion(t.lower,e.lower,o),this.blendBoneQuaternion(t.foot,e.foot,o)}}blendBoneQuaternion(t,e,o){E.copy(t.quaternion),t.quaternion.copy(e).slerp(E,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=C.copy(o.normal).normalize(),n=O.copy(o.forward);if(n.addScaledVector(r,-n.dot(r)),n.lengthSq()<1e-8){const o=this.resolveFootAxes(t,e);n.copy(o.forward).addScaledVector(r,-o.forward.dot(r))}if(n.lengthSq()<1e-8)return;n.normalize();const l=q.crossVectors(r,n);if(l.lengthSq()<1e-8)return;l.normalize(),n.copy(V.crossVectors(l,r)).normalize(),j.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),E.setFromRotationMatrix(j),Q.makeBasis(l,r,n),N.setFromRotationMatrix(Q);const a=H.copy(N).multiply(z.copy(E).invert()),h=this.getCurrentWorldQuaternion(e.parent,z),c=N.copy(h).invert().multiply(a),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,y.clamp(d,0,1))}getMixer(){return this.mixer}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null,this.fullBodyTimer=0}requestSequenceAnimationRelease(){this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationReleasePending=!0,this.sequenceAnimationReleaseFrames=1,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null}cancelRootMotionAction(t){null!=t&&this.fullBodyAction!==t||(this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.fullBodyAction?.stop(),this.fullBodyAction=null,this.fullBodyTimer=0)}beginExternalAnimationControl(t,e={}){it(null!=this.mixer,"Can't begin external control before setup is called"),this.assertClipRigCompatible(t),this.mixer.stopAllAction(),this.currentFullBodyPriority=99,this.fullBodyTimer=0;const o=this.mixer.clipAction(t);return o.setLoop(c,1),o.clampWhenFinished=!0,o.timeScale=e.timeScale??1,o.reset(),o.play(),this.fullBodyAction=o,this.externalControlActive=!0,o}syncMovementSpeed(t){if(null!=t){const e=t.getClip();if(e instanceof s&&e.fixedInPlace&&null!=this.movementSpeed){t.timeScale=e.duration/e.displacement*this.movementSpeed;const o=this.mixer.getRoot();o instanceof h&&(t.timeScale/=o.scale.x)}}}playStateMachine(t){this.stateMachines.push(t)}playUpperStateMachine(t){this.upperStateMachines.push(t)}removeStateMachine(t){const e=this.stateMachines.indexOf(t);e>=0&&this.stateMachines.splice(e,1)}removeUpperStateMachine(t){const e=this.upperStateMachines.indexOf(t);e>=0&&this.upperStateMachines.splice(e,1)}playUpper(t,e={}){this.assertClipRigCompatible(t);const o=e?.priority??1;o<this.currentUpperBodyPriority||(this.currentUpperBodyPriority=o,this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1,this.upperBodyTimer=0,this.upperBodyOverride=!0,this.overrideFadeTimeUpper=e.fadeTime)}play(t,e={}){it(null!=this.mixer,"Can't play animation before setup is called"),this.assertClipRigCompatible(t);const o=e.priority??1;o<this.currentFullBodyPriority||(this.currentFullBodyPriority=o,this.fullBodyTimer=0,e.sequenceControlled&&(this.sequenceAnimationControlled=!0,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0),this.upperBodyOverride||(this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1),this.fullBodyClip=t,this.fullBodyAction=this.transition(this.fullBodyAction,this.getFullBodyClip(t),e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime)}assertClipRigCompatible(t){const e=B(t);if(e===this.animationRigId||null==e&&null==this.animationRigId)return;const o=`${t.uuid}|${e??""}|${this.animationRigId??""}`;if(!lt.has(o)){if(lt.add(o),null==e||null==this.animationRigId)return void console.warn(`Animation clip "${t.name}" or its character has no rig assigned. Playing without rig compatibility validation for legacy compatibility.`);console.warn(`Animation clip "${t.name}" targets rig ${e??"no rig"}, but this character uses rig ${this.animationRigId??"no rig"}. Generate and assign a retargeted clip for the character rig.`)}}onActionDone(t){return new Promise(e=>{const o=i=>{i.action===t&&(e(i.action),this.mixer.removeEventListener("finished",o))};this.mixer.addEventListener("finished",o)})}transition(t,e,o={}){const s=o?.fadeTime??this.fadeTime;if(null!=t&&t.getClip().uuid===e.uuid)return t.isRunning()||!1!==o.loop||!t.clampWhenFinished||o.sequenceControlled?(t.isRunning()||(t.reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play(),!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0)),t):t;if(i(t)){const i=t,r=this.mixer.clipAction(e);r.reset(),null!=o.offset&&(r.time=o.offset),r.play(),r.enabled=!0,r.setEffectiveTimeScale(1),r.weight=1,i.crossFadeTo(r,s,!1),t=r}else(t=this.mixer.clipAction(e)).reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play();return!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0),t}};tt=t([o({inEditor:!0})],tt);export{tt as CharacterAnimationComponent};function et(t,e){if(null==t)return e;const o=e.clone();D(o,B(e));const i=new Set(t.map(t=>t.name));return o.tracks=o.tracks.filter(t=>i.has(t.name.split(".")[0])),o}function ot(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof a)}function it(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function st(t,e){const o=new Map;return(i,...s)=>{const r=t(i);return o.has(r)||o.set(r,e(i,...s)),o.get(r)}}function rt(t){let e;return t.traverse(t=>{(t instanceof a||t.isBone)&&null==e&&(e=t)}),e}function nt(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}const lt=new Set;/*
1
+ import{__decorate as t}from"tslib";import{ActorComponent as e,Component as o}from"../../../component.js";import{canCrossFadeFromAnimationAction as i}from"../../../../animation/animation-action.js";import{RootMotionClip as s}from"../../../../animation/root-motion.js";import{inject as r}from"../../../../inject.js";import{ViewController as n}from"../../../../services/render.js";import{AnimationMixer as l,Bone as a,Object3D as h,LoopOnce as c,Raycaster as d,Vector3 as p,SkinnedMesh as u,Skeleton as f,Quaternion as g,Matrix4 as m,MathUtils as y,ArrowHelper as k,Group as S}from"three";import{getCharacterMovementLike as w}from"./character-movement-like.js";import{CCDIKSolver as b}from"three/addons/animation/CCDIKSolver.js";import{World as v}from"../../../../services/world.js";import{PhysicsSystem as x,RayTestResult as L}from"../../../../services/physics/physics-system.js";import{ArrayMap as I}from"../../../../../utils/collections.js";import{getAnimationClipRigId as P,getAnimationRigChainBoneNames as B,getAnimationRigDataFromObject as R,getAnimationRigIdFromObject as F,setAnimationClipRigId as D}from"../../../../animation/retarget.js";const A=new p(0,-1,0),M=new p(0,1,0),W=new p(1,1,1),T=new g,C=new p,O=new p,q=new p,V=new p,E=new p,U=new g,N=new g,H=new g,z=new g,j=new m,Q=new m,G=new p(1,0,0),_=new p(0,1,0),$=new p(0,0,1);function K(){return{point:new p,normal:new p,hasNormal:!1}}const Y=["mixamorigHips","Hips","hips","Pelvis","pelvis"],J={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},X={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},Z=["left","right"];let tt=class extends e{constructor(){super(...arguments),this.viewController=r(n),this.poseProcessors=new I,this.stateMachines=[],this.upperStateMachines=[],this.fadeTime=.2,this.movementSpeed=null,this.upperBodyTimer=0,this.upperBodyOverride=!1,this.fullBodyTimer=0,this.currentFullBodyPriority=-1,this.currentUpperBodyPriority=-1,this.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.externalControlActive=!1,this.world=r(v),this.physicsSystem=r(x),this._footIkEnabled=!1,this.footIkMoving=!1,this.footIkRayStartHeight=.5,this.footIkRayLength=1.5,this.footIkRaycastMode="physics",this.footIkFootOffset=.08,this.footIkAutoContactOffset=!1,this.footIkPositionLerpSpeed=28,this.footIkRotationLerpSpeed=14,this.footIkWeightInSpeed=34,this.footIkWeightOutSpeed=30,this.footIkMaxSlopeAngleDeg=40,this.footIkForwardSampleDistance=.14,this.footIkSideSampleDistance=.08,this.footIkMaxHorizontalOffset=.22,this.footIkMaxVerticalOffsetDown=.75,this.footIkMaxVerticalOffsetUp=.2,this.footIkPelvisEnabled=!0,this.footIkPelvisBone="mixamorigHips",this.footIkPelvisLerpSpeed=24,this.footIkPelvisMaxOffsetDown=.4,this.footIkPelvisMaxOffsetUp=.08,this.footIkRequireGrounded=!0,this.footIkSimpleTiltOnly=!1,this.footIkDebug=!1,this.footIkDebugNormalLength=.25,this.footIkDebugAxisLength=.2,this.footIkExtraClearance=.01,this.footIkPlantReleaseUpSpeed=.08,this.footIkPlantReleaseExtension=.9,this.footIkPlantAttachExtension=.96,this.footIkPlantReleaseLift=.055,this.footIkPlantAttachLift=.02,this.leftLegIkBones={upperLeg:"mixamorigLeftUpLeg",lowerLeg:"mixamorigLeftLeg",foot:"mixamorigLeftFoot"},this.rightLegIkBones={upperLeg:"mixamorigRightUpLeg",lowerLeg:"mixamorigRightLeg",foot:"mixamorigRightFoot"},this.ikPelvisOffsetY=0,this.ikPelvisDescendantStack=[],this.ikWorldUpdateNodes=[],this.footIkStateReset=!0,this.ikLegState={left:{targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1},right:{targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1}},this.ikWarnedMissingBones=!1,this.raycaster=new d,this.raycastIntersections=[],this.footIkRayTo=new p,this.footIkRayTestResult=new L,this.footIkRayTestOptions={debug:!1,excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:K(),toe:K(),heel:K(),side:K()},this.footIkAxesScratch={up:new p,forward:new p,right:new p},this.footIkSampleAxesScratch={forward:new p,right:new p},this.footIkScratch={footWorldPos:new p,centerRayStart:new p,toeRayStart:new p,heelRayStart:new p,sideRayStart:new p,desiredTargetPos:new p,desiredNormal:new p,desiredForward:new p,debugRayEndA:new p,debugRayEndB:new p,debugRayEndC:new p,debugRayEndD:new p,debugRayEndE:new p,debugRayEndF:new p},this.ikPreSolve={left:{upper:new g,lower:new g,foot:new g},right:{upper:new g,lower:new g,foot:new g}},this.getFullBodyClip=st(t=>t.uuid,t=>et(this.fullBodyMask,t)),this.getUpperBodyClip=st(t=>t.uuid,t=>et(this.upperBodyMask,t))}get footIkEnabled(){return this._footIkEnabled}set footIkEnabled(t){this._footIkEnabled!==t&&(this._footIkEnabled=t,null!=this.ikRoot&&(this.disposeFootIkDebug(),this.initializeFootIk(this.ikRoot,this.ikRootBone),this.syncFootIkDebug()))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=w(this.actor),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,A),this.raycaster.near=0,this.raycaster.far=e,this.raycastIntersections.length=0,this.raycaster.intersectObject(i,!0,this.raycastIntersections);for(const t of this.raycastIntersections)if(!(this.isFootIkDebugObject(t.object)||this.isRelatedToActorHierarchy(t.object)||this.isSkinnedMeshObject(t.object)))return o.point.copy(t.point),null!=t.face?(o.normal.copy(t.face.normal).transformDirection(t.object.matrixWorld).normalize(),o.hasNormal=!0):o.hasNormal=!1,this.raycastIntersections.length=0,!0;return this.raycastIntersections.length=0,!1}rayTestDown(t,e,o){const i=this.footIkRayTo.copy(t).addScaledVector(A,e),s=this.physicsSystem.rayTest(t,i,this.footIkRayTestResult,this.footIkRayTestOptions);return!!s.hasHit&&(o.point.copy(s.hitPoint),o.normal.copy(s.hitNormal),o.normal.lengthSq()>1e-8?(o.normal.normalize(),o.hasNormal=!0):o.hasNormal=!1,!0)}isRelatedToActorHierarchy(t){const e=this.actor?.object;return null!=e&&null!=t&&(nt(t,e)||nt(e,t))}isFootIkDebugObject(t){let e=t;for(;null!=e;){if(!0===e.userData?.footIkDebug)return!0;e=e.parent}return!1}isSkinnedMeshObject(t){let e=t;for(;null!=e;){if(e instanceof u||!0===e.isSkinnedMesh)return!0;e=e.parent}return!1}getRootMotionAction(){if(this.fullBodyAction.getClip()instanceof s)return this.fullBodyAction}getFullBodyAction(){return this.fullBodyAction}setup(t,e,o){null!=e&&(this.upperBodyMask=ot(e),this.fullBodyMask=function(t,e){const o=new Set(ot(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof a||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(rt(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new l(t),this.animationRigId=F(t),this.animationRigData=R(t),this.ikRoot=t,this.ikRootBone=o,this.disposeFootIkDebug(),this.initializeFootIk(t,o),this.syncFootIkDebug()}updateStateMachines(t){this.stateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o&&this.play(o,{priority:e.current.options.priority??0,loop:e.current.options.loop??!0})}),this.upperStateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o?this.playUpper(o,{priority:e.current.options.priority??0,loop:e.current.options.loop??!0}):this.play(this.fullBodyClip)})}addPoseProcessor(t){const e={id:t.id,phase:t.phase??"afterMixer",order:t.order??0,update:t.update};this.removePoseProcessor(e.id);const o=this.poseProcessors.get(e.phase);let i=o.findIndex(t=>t.order>e.order);return-1===i&&(i=o.length),o.splice(i,0,e),()=>{const t=o.indexOf(e);-1!==t&&(o.splice(t,1),0===o.length&&this.poseProcessors.delete(e.phase))}}removePoseProcessor(t){for(const[e,o]of this.poseProcessors.entries()){const i=o.findIndex(e=>e.id===t);if(-1!==i)return o.splice(i,1),void(0===o.length&&this.poseProcessors.delete(e))}}runPoseProcessors(t,e){if(0===this.poseProcessors.size||null==this.mixer||!this.poseProcessors.present(t))return;const o=this.mixer.getRoot();if(!(o instanceof h))return;const i=this.poseProcessorContext??(this.poseProcessorContext={deltaTime:e,phase:t,animation:this,mixer:this.mixer,root:o});i.deltaTime=e,i.phase=t,i.mixer=this.mixer,i.root=o;const s=this.poseProcessors.get(t);for(let t=0;t<s.length;t++)s[t].update(i)}updateInternal(t){if(null==this.mixer)return;if(this.externalControlActive)return;this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1);let e=!1;this.sequenceAnimationReleasePending&&(this.sequenceAnimationReleaseFrames>0?(e=!0,this.sequenceAnimationReleaseFrames--):(this.sequenceAnimationReleasePending=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationControlled=!1,this.overrideFadeTime=null,this.fullBodyTimer=0)),this.upperBodyAction&&this.upperBodyOverride&&this.upperBodyAction.getClip().duration-2*(this.overrideFadeTimeUpper??this.fadeTime)<this.upperBodyTimer&&(this.upperBodyOverride=!1,null!=this.fullBodyClip&&this.transition(this.upperBodyAction,this.getUpperBodyClip(this.fullBodyClip)),this.upperBodyAction=null,this.overrideFadeTimeUpper=null),!this.sequenceAnimationControlled&&!this.sequenceAnimationReleasePending&&this.fullBodyAction&&this.fullBodyAction.loop===c&&this.fullBodyAction.getClip().duration-2*(this.overrideFadeTime??this.fadeTime)<this.fullBodyTimer&&(this.currentFullBodyPriority=-1,this.overrideFadeTime=null),null!=this.characterMovement&&(this.movementSpeed=this.characterMovement.horizontalSpeed),e||this.updateStateMachines(t),this.syncMovementSpeed(this.fullBodyAction),this.upperBodyOverride||this.syncMovementSpeed(this.upperBodyAction),this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t)}initializeFootIk(t,e){if(this.ikSolver=null,this.ikSkinnedMesh=null,this.ikBoneRefs=null,this.ikLegLengths=null,this.ikPelvisBone=null,this.ikPelvisOffsetY=0,this.ikFootAxes=null,this.ikTargetBones=null,this.ikWorldUpdateNodes.length=0,this.footIkStateReset=!0,this.ikWarnedMissingBones=!1,this.ikLegState.left.weight=0,this.ikLegState.right.weight=0,!this.footIkEnabled)return;const o=this.findFirstSkinnedMesh(t);if(null==o||null==o.skeleton)return;this.ikSkinnedMesh=o,t.updateWorldMatrix(!0,!0);const i=o.skeleton,s=B(this.animationRigData,"leftLeg"),r=B(this.animationRigData,"rightLeg"),n=this.resolveLegBoneRefs(i,this.leftLegIkBones,J,s),l=this.resolveLegBoneRefs(i,this.rightLegIkBones,X,r);if(null==n||null==l)return void(this.ikWarnedMissingBones||(this.ikWarnedMissingBones=!0,console.warn(`[CharacterAnimationComponent] Foot IK disabled: missing leg bones. Left=${this.leftLegIkBones.upperLeg}/${this.leftLegIkBones.lowerLeg}/${this.leftLegIkBones.foot}, Right=${this.rightLegIkBones.upperLeg}/${this.rightLegIkBones.lowerLeg}/${this.rightLegIkBones.foot}`)));this.ikBoneRefs={left:n,right:l},this.ikLegLengths={left:this.computeLegLengths(n),right:this.computeLegLengths(l)},this.ikFootAxes={left:this.detectFootAxisBasis(n.foot),right:this.detectFootAxisBasis(l.foot)};const h=this.animationRigData?.bones.find(t=>t.id===this.animationRigData?.pelvisBoneId)?.name;this.ikPelvisBone=this.resolvePelvisBone(i,n,l,h),this.rebuildFootIkWorldUpdateNodes(),this.ikLegState.left.targetPosition.copy(n.foot.getWorldPosition(C)),this.ikLegState.right.targetPosition.copy(l.foot.getWorldPosition(C)),this.ikLegState.left.normal.set(0,1,0),this.ikLegState.right.normal.set(0,1,0),this.ikLegState.left.pitch=0,this.ikLegState.right.pitch=0,this.ikLegState.left.contactOffset=this.estimateFootContactOffset(i,"left",n.foot),this.ikLegState.right.contactOffset=this.estimateFootContactOffset(i,"right",l.foot),this.ikLegState.left.planted=!1,this.ikLegState.right.planted=!1,this.ikLegState.left.lastFootWorldPos.copy(n.foot.getWorldPosition(C)),this.ikLegState.right.lastFootWorldPos.copy(l.foot.getWorldPosition(C)),this.ikLegState.left.hasLastFootSample=!1,this.ikLegState.right.hasLastFootSample=!1;const c=this.resolveFootAxes("left",n.foot),d=this.resolveFootAxes("right",l.foot);this.ikLegState.left.forward.copy(c.forward),this.ikLegState.right.forward.copy(d.forward);const p=e??rt(t);if(null==p)return;let u=i.getBoneByName("_IKTargetLeftFoot"),g=i.getBoneByName("_IKTargetRightFoot"),y=!1;if(null==u&&(u=new a,u.name="_IKTargetLeftFoot",p.add(u),y=!0),null==g&&(g=new a,g.name="_IKTargetRightFoot",p.add(g),y=!0),this.setBoneWorldPosition(u,n.foot.getWorldPosition(C)),this.setBoneWorldPosition(g,l.foot.getWorldPosition(C)),y||i.bones.indexOf(u)<0||i.bones.indexOf(g)<0){const e=i.bones.slice(),o=i.boneInverses.map(t=>t.clone());e.indexOf(u)<0&&(e.push(u),o.push((new m).copy(u.matrixWorld).invert())),e.indexOf(g)<0&&(e.push(g),o.push((new m).copy(g.matrixWorld).invert()));const s=new f(e,o);t.traverse(t=>{const e=t;!0===e.isSkinnedMesh&&e.skeleton===i&&e.bind(s,e.bindMatrix)})}this.ikTargetBones={left:u,right:g},this.rebuildFootIkWorldUpdateNodes();const k=o.skeleton.bones,S={target:k.indexOf(u),effector:k.indexOf(n.foot),links:[{index:k.indexOf(n.lower)},{index:k.indexOf(n.upper)}],iteration:8},w={target:k.indexOf(g),effector:k.indexOf(l.foot),links:[{index:k.indexOf(l.lower)},{index:k.indexOf(l.upper)}],iteration:8};if(S.target<0||S.effector<0||S.links.some(t=>t.index<0)||w.target<0||w.effector<0||w.links.some(t=>t.index<0))return console.warn("[CharacterAnimationComponent] Foot IK disabled: failed to resolve IK indexes in skeleton."),void(this.ikSolver=null);this.ikSolver=new b(o,[S,w])}findFirstSkinnedMesh(t){let e;return t.traverse(t=>{null==e&&(t instanceof u||!0===t.isSkinnedMesh)&&(e=t)}),e}resolveLegBoneRefs(t,e,o,i=[]){const s=this.findBoneByNames(t,[i[0],e.upperLeg,...o.upper].filter(t=>null!=t)),r=this.findBoneByNames(t,[i.at(-2),e.lowerLeg,...o.lower].filter(t=>null!=t)),n=this.findBoneByNames(t,[i.at(-1),e.foot,...o.foot].filter(t=>null!=t));if(null!=s&&null!=r&&null!=n)return{upper:s,lower:r,foot:n}}findBoneByNames(t,e){for(const o of e){const e=t.getBoneByName(o);if(null!=e)return e}}resolvePelvisBone(t,e,o,i){const s=this.findBoneByNames(t,[i,this.footIkPelvisBone,...Y].filter(t=>null!=t));if(null!=s)return s;const r=e.upper.parent,n=o.upper.parent;return null!=r&&r===n&&(r instanceof a||!0===r.isBone)||null!=r&&(r instanceof a||!0===r.isBone)?r:void 0}computeLegLengths(t){const e=t.upper.getWorldPosition(C),o=t.lower.getWorldPosition(O),i=t.foot.getWorldPosition(q),s=e.distanceTo(o),r=o.distanceTo(i);return{upper:s,lower:r,total:s+r}}setBoneWorldPosition(t,e){const o=t.parent;null==o?t.position.copy(e):t.position.copy(C.copy(e).applyMatrix4(j.copy(o.matrixWorld).invert())),t.quaternion.copy(T),t.scale.copy(W),t.updateMatrixWorld(!0)}syncFootIkDebug(){this.footIkDebug&&null!=this.ikRoot?(null!=this.ikDebugRoot&&null!=this.ikDebugLegs||(this.ikDebugRoot=new S,this.ikDebugRoot.name="FootIKDebug",this.ikDebugRoot.userData.footIkDebug=!0,this.ikDebugLegs={left:this.createDebugLeg("LeftFootIK",53503),right:this.createDebugLeg("RightFootIK",16755200)},this.ikDebugRoot.add(this.ikDebugLegs.left.root,this.ikDebugLegs.right.root),this.world.scene.add(this.ikDebugRoot)),this.ikDebugRoot.visible=!0):null!=this.ikDebugRoot&&(this.ikDebugRoot.visible=!1)}disposeFootIkDebug(){null!=this.ikDebugRoot&&(this.ikDebugRoot.removeFromParent(),this.ikDebugRoot.clear()),this.ikDebugRoot=null,this.ikDebugLegs=null}createDebugLeg(t,e){const o=new S;o.name=t,o.userData.footIkDebug=!0;const i=this.createDebugArrow(e),s=this.createDebugArrow(e),r=this.createDebugArrow(e),n=this.createDebugArrow(e),l=this.createDebugArrow(65280),a=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,l,a,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:l,footUp:a,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new k(M,new p,.001,t);return e.userData.footIkDebug=!0,e.traverse(t=>{t.userData.footIkDebug=!0,t.raycast=()=>{}}),e.visible=!1,e}setDebugArrow(t,e,o){C.subVectors(o,e);const i=C.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(C.multiplyScalar(1/i)),t.setLength(i,Math.min(.08,.25*i),Math.min(.05,.2*i)))}resetDebugVisibility(){null!=this.ikDebugLegs&&(this.ikDebugLegs.left.rayCenter.visible=!1,this.ikDebugLegs.left.rayToe.visible=!1,this.ikDebugLegs.left.rayHeel.visible=!1,this.ikDebugLegs.left.raySide.visible=!1,this.ikDebugLegs.left.hitNormal.visible=!1,this.ikDebugLegs.left.footUp.visible=!1,this.ikDebugLegs.left.footToTarget.visible=!1,this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.rayCenter.visible=!1,this.ikDebugLegs.right.rayToe.visible=!1,this.ikDebugLegs.right.rayHeel.visible=!1,this.ikDebugLegs.right.raySide.visible=!1,this.ikDebugLegs.right.hitNormal.visible=!1,this.ikDebugLegs.right.footUp.visible=!1,this.ikDebugLegs.right.footToTarget.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1)}updateFootIk(t){if(this.syncFootIkDebug(),!this.footIkEnabled||null==this.ikBoneRefs||null==this.ikRoot)return void this.resetDebugVisibility();if(!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.footIkStateReset||(this.syncFootIkWorldMatrices(),this.resetFootIkState(),this.footIkStateReset=!0),void this.resetDebugVisibility();this.syncFootIkWorldMatrices(),this.footIkStateReset=!1;const e=this.characterMovement?.isGrounded??!0;return this.footIkSimpleTiltOnly?(this.updatePelvisOffset(t,!1),this.updateLegTiltSimple("left",this.ikBoneRefs.left.foot,this.ikLegState.left,e,t),void this.updateLegTiltSimple("right",this.ikBoneRefs.right.foot,this.ikLegState.right,e,t)):null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver?(this.updatePelvisOffset(t,!1),void this.resetDebugVisibility()):(this.updateLegIkTarget("left",this.ikBoneRefs.left,this.ikLegLengths.left,this.ikTargetBones.left,this.ikLegState.left,e,t),this.updateLegIkTarget("right",this.ikBoneRefs.right,this.ikLegLengths.right,this.ikTargetBones.right,this.ikLegState.right,e,t),this.updatePelvisOffset(t,!0),this.setBoneWorldPosition(this.ikTargetBones.left,this.ikLegState.left.targetPosition),this.setBoneWorldPosition(this.ikTargetBones.right,this.ikLegState.right.targetPosition),this.ikPreSolve.left.upper.copy(this.ikBoneRefs.left.upper.quaternion),this.ikPreSolve.left.lower.copy(this.ikBoneRefs.left.lower.quaternion),this.ikPreSolve.left.foot.copy(this.ikBoneRefs.left.foot.quaternion),this.ikPreSolve.right.upper.copy(this.ikBoneRefs.right.upper.quaternion),this.ikPreSolve.right.lower.copy(this.ikBoneRefs.right.lower.quaternion),this.ikPreSolve.right.foot.copy(this.ikBoneRefs.right.foot.quaternion),null!=this.ikDebugLegs&&(this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1),this.ikSolver.update(),this.blendLegAfterSolve(this.ikBoneRefs.left,this.ikPreSolve.left,this.ikLegState.left.weight),this.blendLegAfterSolve(this.ikBoneRefs.right,this.ikPreSolve.right,this.ikLegState.right.weight),this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),void this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right))}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of Z){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=C.setFromMatrixPosition(e.foot.matrixWorld);o.targetPosition.copy(i),o.lastFootWorldPos.copy(i),o.hasLastFootSample=!0,o.weight=0,o.normal.set(0,1,0);const s=this.resolveFootAxes(t,e.foot,this.footIkAxesScratch);o.forward.copy(s.forward),o.pitch=0,this.footIkAutoContactOffset?o.contactOffset=Math.max(o.contactOffset,this.footIkFootOffset+this.footIkExtraClearance):o.contactOffset=this.footIkFootOffset+this.footIkExtraClearance,o.planted=!1}this.ikPelvisOffsetY=0}}updatePelvisOffset(t,e){if(null==this.ikPelvisBone)return;let o=0;if(e&&this.footIkPelvisEnabled&&null!=this.ikBoneRefs&&null!=this.ikLegLengths){this.ikLegState.left.top=!1,this.ikLegState.right.top=!1;for(const t of Z){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=C.setFromMatrixPosition(e.upper.matrixWorld),n=.998*i.total,l=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(l>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-l)}o=y.clamp(o,-this.footIkPelvisMaxOffsetDown,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=y.lerp(this.ikPelvisOffsetY,o,i);const s=O.setFromMatrixPosition(this.ikPelvisBone.matrixWorld),r=q.copy(s).addScaledVector(M,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(r.applyMatrix4(j.copy(this.ikPelvisBone.parent.matrixWorld).invert())),this.updatePelvisWorldTranslation(s)}updatePelvisWorldTranslation(t){const e=this.ikPelvisBone;if(null==e)return;e.updateMatrix(),null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix),e.matrixWorldNeedsUpdate=!1;const o=e.matrixWorld.elements,i=o[12]-t.x,s=o[13]-t.y,r=o[14]-t.z;if(0===i&&0===s&&0===r)return;const n=this.ikPelvisDescendantStack;n.length=0;for(let t=0;t<e.children.length;t++)n.push(e.children[t]);for(;n.length>0;){const t=n.pop(),e=t.matrixWorld.elements;e[12]+=i,e[13]+=s,e[14]+=r,t.matrixWorldNeedsUpdate=!1;for(let e=0;e<t.children.length;e++)n.push(t.children[e])}}rebuildFootIkWorldUpdateNodes(){const t=this.ikRoot,e=this.ikBoneRefs;if(null==t||null==e)return void(this.ikWorldUpdateNodes.length=0);const o=new Set,i=[this.ikPelvisBone,e.left.upper,e.left.lower,e.left.foot,e.right.upper,e.right.lower,e.right.foot,this.ikTargetBones?.left,this.ikTargetBones?.right];for(const e of i){let i=e;for(;null!=i&&(o.add(i),i!==t);)i=i.parent??void 0}this.ikWorldUpdateNodes.length=0,t.traverse(t=>{o.has(t)&&this.ikWorldUpdateNodes.push(t)})}syncFootIkWorldMatrices(){const t=this.ikRoot;if(null!=t){t.updateWorldMatrix(!0,!1);for(const e of this.ikWorldUpdateNodes)e!==t&&(e.matrixAutoUpdate&&e.updateMatrix(),e.matrixWorldAutoUpdate&&(null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix)),e.matrixWorldNeedsUpdate=!1)}}computeFootVerticalSpeed(t,e,o){return!t.hasLastFootSample||o<=1e-6?0:(e.y-t.lastFootWorldPos.y)/o}updateFootSample(t,e){t.lastFootWorldPos.copy(e),t.hasLastFootSample=!0}estimateFootContactOffset(t,e,o){const i=this.footIkFootOffset+this.footIkExtraClearance;if(!this.footIkAutoContactOffset)return i;const s=t.bones.indexOf(o);if(s<0)return i;const r=t.boneInverses[s];if(null==r)return i;const n=this.ikFootAxes?.[e]??this.detectFootAxisBasis(o),l=o.getWorldPosition(O),h=q.copy(n.upLocal).applyQuaternion(this.getCurrentWorldQuaternion(o,U)).normalize();let c=0;return o.traverse(e=>{if(!(e instanceof a)||e===o)return;const i=t.bones.indexOf(e);if(i<0)return;const s=j.copy(t.boneInverses[i]).invert(),n=Q.copy(r).multiply(s),d=C.setFromMatrixPosition(n),p=V.copy(d).applyMatrix4(o.matrixWorld).sub(l);c=Math.min(c,p.dot(h))}),Math.max(i,-c+this.footIkExtraClearance)}shouldPlantFoot(t,e,o,i,s,r){if(!e||!o)return!1;const n=this.footIkPlantReleaseExtension,l=this.footIkPlantAttachExtension,a=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>a)):s>=l&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=C.setFromMatrixPosition(t.upper.matrixWorld),i=O.setFromMatrixPosition(t.foot.matrixWorld),s=o.distanceTo(i);return e.total<=1e-6?1:y.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=V.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(M),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const l=Math.sqrt(n),a=r-l,h=r+l;return a>=0?a:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,l=r.footWorldPos.setFromMatrixPosition(e.matrixWorld),a=this.computeFootVerticalSpeed(o,l,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(l).addScaledVector(M,this.footIkRayStartHeight),p=r.toeRayStart.copy(d).addScaledVector(c.forward,this.footIkForwardSampleDistance),u=r.heelRayStart.copy(d).addScaledVector(c.forward,-this.footIkForwardSampleDistance),f=r.sideRayStart.copy(d).addScaledVector(c.right,this.footIkSideSampleDistance),g=this.getFirstGroundHit(d,n.center),m=this.getFirstGroundHit(p,n.toe),k=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),w=r.desiredNormal.set(0,1,0),b=r.desiredForward.copy(c.forward);let v=0,x=0,L=this.footIkWeightOutSpeed;const I=null!=g||null!=m||null!=k;let P=l.y;null!=g?P=g.point.y:null!=m&&null!=k?P=.5*(m.point.y+k.point.y):null!=m?P=m.point.y:null!=k&&(P=k.point.y);const B=this.ikBoneRefs?.[t],R=this.ikLegLengths?.[t],F=null!=B&&null!=R?this.computeLegExtensionRatio(B,R):1,D=Math.max(0,l.y-P,l.y-o.targetPosition.y),A=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,I,a,F,D);A?this.computeDesiredGroundNormal(c,g,m,k,S,w)&&(this.computeDesiredFootForward(c.forward,c.right,w,m,k,b),v=this.computeDesiredPitchAngle(m,k,c.forward),x=1,L=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,w,null,null,b);const W=1-Math.exp(-this.footIkPositionLerpSpeed*s),T=1-Math.exp(-L*s);o.normal.lerp(w,W).normalize(),o.forward.lerp(b,W).normalize(),o.pitch=y.lerp(o.pitch,v,W),o.weight=y.lerp(o.weight,x,T),o.planted=A&&x>.001,this.updateFootSample(o,l),this.applySimpleFootPitch(t,e,o),this.updateLegDebug(t,{footWorldPos:l,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:m,heelHit:k,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const l=this.footIkScratch,a=this.footIkHits,h=e.foot,c=l.footWorldPos.setFromMatrixPosition(h.matrixWorld),d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=l.centerRayStart.copy(c).addScaledVector(M,this.footIkRayStartHeight),g=l.toeRayStart.copy(f).addScaledVector(u.forward,this.footIkForwardSampleDistance),m=l.heelRayStart.copy(f).addScaledVector(u.forward,-this.footIkForwardSampleDistance),k=l.sideRayStart.copy(f).addScaledVector(u.right,this.footIkSideSampleDistance),S=this.getFirstGroundHit(f,a.center),w=this.getFirstGroundHit(g,a.toe),b=this.getFirstGroundHit(m,a.heel),v=this.getFirstGroundHit(k,a.side),x=l.desiredTargetPos.copy(c),L=l.desiredNormal.set(0,1,0),I=l.desiredForward.copy(u.forward);let P=0,B=0,R=this.footIkWeightOutSpeed;const F=null!=S||null!=w||null!=b;let D=c.y;null!=S?D=S.point.y:null!=w&&null!=b?D=.5*(w.point.y+b.point.y):null!=w?D=w.point.y:null!=b&&(D=b.point.y);const A=this.computeLegExtensionRatio(e,o),W=Math.max(0,c.y-D,c.y-s.targetPosition.y),T=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,F,d,A,W);if(T){if(x.copy(c),this.computeDesiredGroundNormal(u,S,w,b,v,L)){this.computeDesiredFootForward(u.forward,u.right,L,w,b,I),P=this.computeDesiredPitchAngle(w,b,u.forward);const t=Math.max(0,Math.sin(P))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);x.y=D+e+t,s.top&&(x.y-=this.ikPelvisOffsetY/2),B=1,R=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,L,null,null,I),x.copy(c),x.y+=this.footIkFootOffset;const C=1-Math.exp(-this.footIkPositionLerpSpeed*n),O=1-Math.exp(-R*n);s.targetPosition.lerp(x,C),this.clampDesiredFootTarget(e,o,c,s.targetPosition),s.normal.lerp(L,C).normalize(),s.forward.lerp(I,C).normalize(),s.pitch=y.lerp(s.pitch,P,C),s.weight=y.lerp(s.weight,B,O),s.planted=T&&B>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.updateLegDebug(t,{footWorldPos:c,centerRayStart:f,toeRayStart:g,heelRayStart:m,sideRayStart:k,centerHit:S,toeHit:w,heelHit:b,sideHit:v,desiredNormal:L,desiredTargetPos:s.targetPosition,weight:s.weight})}updateLegDebug(t,e){if(!this.footIkDebug||null==this.ikDebugLegs||null==this.ikBoneRefs)return;const o=this.ikDebugLegs[t],i=this.ikBoneRefs[t],s=this.resolveFootAxes(t,i.foot,this.footIkAxesScratch),r=this.footIkScratch,n=e.centerHit?.point??r.debugRayEndA.copy(e.centerRayStart).addScaledVector(A,this.footIkRayLength),l=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(A,this.footIkRayLength),a=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(A,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(A,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,l),this.setDebugArrow(o.rayHeel,e.heelRayStart,a),this.setDebugArrow(o.raySide,e.sideRayStart,h);const c=e.centerHit?.point??e.toeHit?.point??e.heelHit?.point??e.sideHit?.point??e.footWorldPos;this.setDebugArrow(o.hitNormal,c,r.debugRayEndE.copy(c).addScaledVector(e.desiredNormal,this.footIkDebugNormalLength)),this.setDebugArrow(o.footUp,e.footWorldPos,r.debugRayEndF.copy(e.footWorldPos).addScaledVector(s.up,this.footIkDebugAxisLength*(.15+e.weight))),this.setDebugArrow(o.footToTarget,e.footWorldPos,e.desiredTargetPos)}getFirstGroundHit(t,e){return"physics"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)?e:null:"physicsThenRender"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)||this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null:this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null}resolveGroundSampleAxes(t,e,o,i){const s=o??this.resolveFootAxes(t,e),r=i??{forward:new p,right:new p},n=this.getCurrentWorldDirection(this.actor.object,V);n.addScaledVector(M,-n.dot(M)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(M,-s.forward.dot(M)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const l=E.crossVectors(M,n);return l.lengthSq()<1e-8?l.copy(s.right):l.normalize(),l.dot(s.right)<0&&l.multiplyScalar(-1),r.forward.copy(n),r.right.copy(l),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,V);let l=!1,a=0,h=0;if(null!=o&&null!=i){const e=O.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(a=(o.point.y-i.point.y)/e,l=!0)}if(null!=s&&null!=e){const o=q.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,l=!0)}if(l&&(r.copy(M),r.addScaledVector(t.forward,-a),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():l=!1),l)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),l=!0}return r.dot(M)<0&&r.multiplyScalar(-1),this.clampSlopeNormal(r),!0}computeAverageHitNormal(t,e,o,i,s){s.set(0,0,0);let r=0;return null!=t&&t.hasNormal&&(s.add(t.normal),r++),null!=e&&e.hasNormal&&(s.add(e.normal),r++),null!=o&&o.hasNormal&&(s.add(o.normal),r++),null!=i&&i.hasNormal&&(s.add(i.normal),r++),0===r||s.lengthSq()<1e-8?null:(s.multiplyScalar(1/r).normalize(),s)}computeDesiredFootForward(t,e,o,i,s,r){null!=i&&null!=s?r.subVectors(i.point,s.point):r.copy(t),r.addScaledVector(o,-r.dot(o)),r.lengthSq()<1e-8&&(r.copy(this.getCurrentWorldDirection(this.actor.object,V)),r.addScaledVector(o,-r.dot(o))),r.lengthSq()<1e-8&&r.crossVectors(o,e),r.lengthSq()<1e-8&&r.set(0,0,1),r.normalize();const n=V.copy(this.getCurrentWorldDirection(this.actor.object,V));n.addScaledVector(o,-n.dot(o)),n.lengthSq()<1e-8&&(n.copy(t),n.addScaledVector(o,-n.dot(o))),n.lengthSq()>1e-8&&n.normalize(),r.dot(n)<0&&r.multiplyScalar(-1)}computeDesiredPitchAngle(t,e,o){if(null==t||null==e)return 0;const i=O.subVectors(t.point,e.point),s=Math.abs(i.dot(o));if(s<1e-5)return 0;const r=t.point.y-e.point.y,n=y.degToRad(this.footIkMaxSlopeAngleDeg);return y.clamp(-Math.atan2(r,s),-n,n)}applySimpleFootPitch(t,e,o){if(null==e.parent||o.weight<=.001)return;const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o.pitch*o.weight;if(Math.abs(s)<=1e-5)return;const r=this.resolveLocalPitchSign(i),n=U.copy(e.quaternion),l=N.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(l))}resolveLocalPitchSign(t){const e=H.setFromAxisAngle(t.rightLocal,.15);return q.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=O.subVectors(i,o),r=s.dot(M),n=q.copy(s).addScaledVector(M,-r),l=n.length();l>this.footIkMaxHorizontalOffset&&l>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/l);const a=y.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(M,a),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(C).clone(),c=O.subVectors(i,h),d=c.length(),p=.995*e.total;d>p&&d>1e-6&&i.copy(h).addScaledVector(c,p/d)}solveTwoBoneLeg(t,e,o){const i=e.upper.getWorldPosition(C).clone(),s=e.lower.getWorldPosition(O).clone(),r=e.foot.getWorldPosition(q).clone(),n=i.distanceTo(s),l=s.distanceTo(r);if(n<1e-5||l<1e-5)return;const a=(new p).subVectors(o,i),h=a.length();if(h<1e-5)return;const c=Math.abs(n-l)+1e-4,d=n+l-1e-4,u=y.clamp(h,c,d),f=a.multiplyScalar(1/h),g=(new p).subVectors(s,i).normalize(),m=(new p).subVectors(r,s).normalize(),k=(new p).crossVectors(g,m);k.lengthSq()<1e-8&&(k.copy(this.getCurrentWorldDirection(this.actor.object,C).cross(M)),k.lengthSq()<1e-8&&k.set(1,0,0)),k.normalize();const S=(u*u+n*n-l*l)/(2*u),w=Math.max(n*n-S*S,0),b=Math.sqrt(w),v=(new p).copy(i).addScaledVector(f,S);let x=(new p).crossVectors(k,f);x.lengthSq()<1e-8&&(x=(new p).crossVectors(f,M),x.lengthSq()<1e-8&&(x=new p(1,0,0))),x.normalize();const L=(new p).copy(v).addScaledVector(x,b),I=(new p).copy(v).addScaledVector(x,-b),P=(new p).subVectors(s,v).dot(x)>=0?L:I;this.rotateBoneToward(e.upper,i,s,P),e.upper.updateMatrixWorld(!0);const B=e.lower.getWorldPosition(O),R=e.foot.getWorldPosition(q);this.rotateBoneToward(e.lower,B,R,o),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,i,P,o)}updateSolveDebug(t,e,o,i){if(!this.footIkDebug||null==this.ikDebugLegs)return;const s=this.ikDebugLegs[t];this.setDebugArrow(s.solveUpper,e,o),this.setDebugArrow(s.solveLower,o,i)}rotateBoneToward(t,e,o,i){const s=(new p).subVectors(o,e),r=(new p).subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>.9999)return;const n=(new g).setFromUnitVectors(s,r),l=this.getCurrentWorldQuaternion(t,U),a=N.copy(n).multiply(l);if(null==t.parent)return void t.quaternion.copy(a);const h=this.getCurrentWorldQuaternion(t.parent,H),c=z.copy(h).invert().multiply(a);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=this.getCurrentWorldQuaternion(t,U),o=this.getCurrentWorldDirection(this.actor.object,C);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:G.clone(),world:G.clone().applyQuaternion(e)},{local:_.clone(),world:_.clone().applyQuaternion(e)},{local:$.clone(),world:$.clone().applyQuaternion(e)}];i.push({local:G.clone().multiplyScalar(-1),world:G.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:_.clone().multiplyScalar(-1),world:_.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:$.clone().multiplyScalar(-1),world:$.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(M);e>r&&(r=e,s=t)}let n=i[0],l=-1/0;for(const t of i){if(Math.abs(t.world.dot(s.world))>.6)continue;const e=Math.abs(t.world.dot(o));e>l&&(l=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const a=s.local.clone().normalize(),h=n.local.clone().normalize(),c=a.clone().cross(h).normalize();return{upLocal:a,forwardLocal:c.clone().cross(a).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new p,forward:new p,right:new p},r=this.getCurrentWorldQuaternion(e,U);return s.up.copy(i.upLocal).applyQuaternion(r).normalize(),s.forward.copy(i.forwardLocal).applyQuaternion(r).normalize(),s.right.copy(i.rightLocal).applyQuaternion(r).normalize(),s}getCurrentWorldQuaternion(t,e){return t.matrixWorld.decompose(E,e,V),e}getCurrentWorldDirection(t,e){const o=t.matrixWorld.elements;return e.set(o[8],o[9],o[10]).normalize()}clampSlopeNormal(t){const e=y.clamp(t.dot(M),-1,1),o=Math.acos(e),i=y.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(M,t,s).normalize()}blendLegAfterSolve(t,e,o){if(!(o>=.999)){if(o<=.001)return t.upper.quaternion.copy(e.upper),t.lower.quaternion.copy(e.lower),void t.foot.quaternion.copy(e.foot);this.blendBoneQuaternion(t.upper,e.upper,o),this.blendBoneQuaternion(t.lower,e.lower,o),this.blendBoneQuaternion(t.foot,e.foot,o)}}blendBoneQuaternion(t,e,o){U.copy(t.quaternion),t.quaternion.copy(e).slerp(U,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=C.copy(o.normal).normalize(),n=O.copy(o.forward);if(n.addScaledVector(r,-n.dot(r)),n.lengthSq()<1e-8){const o=this.resolveFootAxes(t,e);n.copy(o.forward).addScaledVector(r,-o.forward.dot(r))}if(n.lengthSq()<1e-8)return;n.normalize();const l=q.crossVectors(r,n);if(l.lengthSq()<1e-8)return;l.normalize(),n.copy(V.crossVectors(l,r)).normalize(),j.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),U.setFromRotationMatrix(j),Q.makeBasis(l,r,n),N.setFromRotationMatrix(Q);const a=H.copy(N).multiply(z.copy(U).invert()),h=this.getCurrentWorldQuaternion(e.parent,z),c=N.copy(h).invert().multiply(a),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,y.clamp(d,0,1))}getMixer(){return this.mixer}evaluateExternalPose(t=0){null!=this.mixer&&(this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t))}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null,this.fullBodyTimer=0}requestSequenceAnimationRelease(){this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationReleasePending=!0,this.sequenceAnimationReleaseFrames=1,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null}cancelRootMotionAction(t){null!=t&&this.fullBodyAction!==t||(this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.fullBodyAction?.stop(),this.fullBodyAction=null,this.fullBodyTimer=0)}beginExternalAnimationControl(t,e={}){it(null!=this.mixer,"Can't begin external control before setup is called"),this.assertClipRigCompatible(t),this.mixer.stopAllAction(),this.currentFullBodyPriority=99,this.fullBodyTimer=0;const o=this.mixer.clipAction(t);return o.setLoop(c,1),o.clampWhenFinished=!0,o.timeScale=e.timeScale??1,o.reset(),o.play(),this.fullBodyAction=o,this.externalControlActive=!0,o}syncMovementSpeed(t){if(null!=t){const e=t.getClip();if(e instanceof s&&e.fixedInPlace&&null!=this.movementSpeed){t.timeScale=e.duration/e.displacement*this.movementSpeed;const o=this.mixer.getRoot();o instanceof h&&(t.timeScale/=o.scale.x)}}}playStateMachine(t){this.stateMachines.push(t)}playUpperStateMachine(t){this.upperStateMachines.push(t)}removeStateMachine(t){const e=this.stateMachines.indexOf(t);e>=0&&this.stateMachines.splice(e,1)}removeUpperStateMachine(t){const e=this.upperStateMachines.indexOf(t);e>=0&&this.upperStateMachines.splice(e,1)}playUpper(t,e={}){this.assertClipRigCompatible(t);const o=e?.priority??1;o<this.currentUpperBodyPriority||(this.currentUpperBodyPriority=o,this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1,this.upperBodyTimer=0,this.upperBodyOverride=!0,this.overrideFadeTimeUpper=e.fadeTime)}play(t,e={}){it(null!=this.mixer,"Can't play animation before setup is called"),this.assertClipRigCompatible(t);const o=e.priority??1;o<this.currentFullBodyPriority||(this.currentFullBodyPriority=o,this.fullBodyTimer=0,e.sequenceControlled&&(this.sequenceAnimationControlled=!0,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0),this.upperBodyOverride||(this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1),this.fullBodyClip=t,this.fullBodyAction=this.transition(this.fullBodyAction,this.getFullBodyClip(t),e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime)}assertClipRigCompatible(t){const e=P(t);if(e===this.animationRigId||null==e&&null==this.animationRigId)return;const o=`${t.uuid}|${e??""}|${this.animationRigId??""}`;if(!lt.has(o)){if(lt.add(o),null==e||null==this.animationRigId)return void console.warn(`Animation clip "${t.name}" or its character has no rig assigned. Playing without rig compatibility validation for legacy compatibility.`);console.warn(`Animation clip "${t.name}" targets rig ${e??"no rig"}, but this character uses rig ${this.animationRigId??"no rig"}. Generate and assign a retargeted clip for the character rig.`)}}onActionDone(t){return new Promise(e=>{const o=i=>{i.action===t&&(e(i.action),this.mixer.removeEventListener("finished",o))};this.mixer.addEventListener("finished",o)})}transition(t,e,o={}){const s=o?.fadeTime??this.fadeTime;if(null!=t&&t.getClip().uuid===e.uuid)return t.isRunning()||!1!==o.loop||!t.clampWhenFinished||o.sequenceControlled?(t.isRunning()||(t.reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play(),!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0)),t):t;if(i(t)){const i=t,r=this.mixer.clipAction(e);r.reset(),null!=o.offset&&(r.time=o.offset),r.play(),r.enabled=!0,r.setEffectiveTimeScale(1),r.weight=1,i.crossFadeTo(r,s,!1),t=r}else(t=this.mixer.clipAction(e)).reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play();return!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0),t}};tt=t([o({inEditor:!0})],tt);export{tt as CharacterAnimationComponent};function et(t,e){if(null==t)return e;const o=e.clone();D(o,P(e));const i=new Set(t.map(t=>t.name));return o.tracks=o.tracks.filter(t=>i.has(t.name.split(".")[0])),o}function ot(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof a)}function it(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function st(t,e){const o=new Map;return(i,...s)=>{const r=t(i);return o.has(r)||o.set(r,e(i,...s)),o.get(r)}}function rt(t){let e;return t.traverse(t=>{(t instanceof a||t.isBone)&&null==e&&(e=t)}),e}function nt(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}const lt=new Set;/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{__decorate as t,__metadata as o}from"tslib";import{ActorComponent as e,Component as i}from"../component.js";import{Vector3 as s,MathUtils as r,PerspectiveCamera as n,Object3D as h}from"three";import{ViewController as a}from"../../services/render.js";import{DecimalInput as l,RestrictedRotationInput as c}from"../../input/index.js";import{PhysicsSystem as p}from"../../services/physics/physics-system.js";import{Parameter as m}from"../../../shader/parameter.js";import{World as d}from"../../services/world.js";import{inject as u}from"../../inject.js";import{ease as y}from"@hology/nebula";const f=void 0!==window&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);let C=class extends e{constructor(){super(),this.viewController=u(a),this.physicsSystem=u(p),this.aspect=this.viewController.htmlElement.clientWidth/this.viewController.htmlElement.clientHeight,this.near=.1,this.far=500,this.viewAngle=f?30:45,this.collision=!0,this.collisionSphereRadius=.25,this.smoothCamera=!1,this.smoothSpeed=10,this.teleportSnapDistance=5,this.camera=new n(this.viewAngle,this.aspect,this.near,this.far),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetY=2,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=3,this.restrictedDistance=0,this.hasCollisionRestriction=!1,this.rotationInput=new c(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new l(1,0,1),this.offset=new s,this.lookAtOffset=new s(this.offsetX,0,this.offsetZ),this.fixedBehind=!0,this.world=u(d),this.activated=!1,this.isMouseLocked=!1,this.prevFixedBehind=!1,this.blendDurationLeft=0,this.pointerEventsRegistered=!1,this.temporaryControlActive=!1,this.temporaryControlWeight=0,this.temporaryControlTargetWeight=0,this.temporaryControlBlendInDuration=.5,this.temporaryControlBlendOutDuration=.5,this.temporaryControlPositionEnabled=!1,this.temporaryControlBaseFieldOfView=this.camera.fov,this.temporaryControlFieldOfView=null,this.temporaryControlPosition=new s,this.temporaryControlLookAt=new s,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||"mouse"!==t.pointerType||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.element.style.cursor=this.isMouseLocked?"none":"default",this.isMouseLocked||(this.pointerLockInactivatedAt=performance.now())},this.prevLookAt=new s,this.smoothedLookAt=new s,this.previousTargetLookAt=new s,this.hasSmoothedLookAt=!1,this.smoothedRotX=0,this.smoothedRotY=0,this.smoothZoom=0}async onInit(){this.prevFixedBehind=this.fixedBehind,this.world.scene.add(this.camera),this.rotationInput.rotation.copy(this.actor.rotation),this.smoothedRotX=this.rotationInput.rotation.x,this.smoothedRotY=this.rotationInput.rotation.y,this.hasCollisionRestriction=!1,this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.smoothZoom=this.zoomInput.value,this.autoActivate&&this.activate(),this.disposed.subscribe(()=>{this.unregisterPointerEvents()})}activate(){this.activated=!0,this.hasSmoothedLookAt=!1,this.viewController.setCamera(this.camera),this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.registerPointerEvents()}deactivate(){this.activated=!1,this.isMouseLocked=!1,this.unregisterPointerEvents()}setTemporaryControl(t,o,e={}){this.temporaryControlPosition.copy(t),this.temporaryControlLookAt.copy(o),this.temporaryControlPositionEnabled=!0,this.activateTemporaryControl(e)}setTemporaryLookAt(t,o={}){this.temporaryControlLookAt.copy(t),this.temporaryControlPositionEnabled=!1,this.activateTemporaryControl(o)}activateTemporaryControl(t){this.temporaryControlActive||(this.temporaryControlBaseFieldOfView=this.camera.fov),this.temporaryControlFieldOfView=null==t.fieldOfView?null:r.clamp(t.fieldOfView,1,179),null!=t.blendInDuration&&(this.temporaryControlBlendInDuration=Math.max(0,t.blendInDuration)),null!=t.blendOutDuration&&(this.temporaryControlBlendOutDuration=Math.max(0,t.blendOutDuration)),this.temporaryControlActive=!0,this.temporaryControlTargetWeight=1}clearTemporaryControl(t){this.temporaryControlActive&&(null!=t&&(this.temporaryControlBlendOutDuration=Math.max(0,t)),this.temporaryControlTargetWeight=0)}registerPointerEvents(){if(this.pointerEventsRegistered||null==document.body.requestPointerLock)return;const t=this.element;t.addEventListener("pointerdown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!0}unregisterPointerEvents(){if(!this.pointerEventsRegistered)return;const t=this.element;t.removeEventListener("pointerdown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!1}onLateUpdate(t){this.activated&&this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor({ignoreRecentUnlock:t=!1}={}){!t&&null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||this.requestPointerLock()}requestPointerLock(){const t=this.element.getElementsByTagName("canvas")[0];if(null!=t&&t.isConnected&&t.ownerDocument===document&&null!=t.requestPointerLock)try{const o=t.requestPointerLock({unadjustedMovement:!0});o?.catch(()=>this.onPointerLockChange())}catch{this.onPointerLockChange()}else this.onPointerLockChange()}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",null==document.pointerLockElement&&null==document.mozPointerLockElement||window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.fixedBehind!==this.prevFixedBehind?(this.blendDurationLeft=1,this.prevFixedBehind=this.fixedBehind):this.blendDurationLeft>0&&(this.blendDurationLeft-=t);let o=this.zoomInput.value,e=this.rotationInput.rotation.x,i=this.rotationInput.rotation.y;if(this.smoothCamera){const s=1-Math.exp(-this.smoothSpeed*t*2);this.smoothedRotX=r.lerp(this.smoothedRotX,e,s),this.smoothedRotY=r.lerp(this.smoothedRotY,i,s),e=this.smoothedRotX,i=this.smoothedRotY,this.smoothZoom=r.lerp(this.smoothZoom,o,.4*s),o=this.smoothZoom}else this.smoothedRotX=e,this.smoothedRotY=i;const s=r.clamp(this.distance,this.minDistance,Math.max(this.distance*o,this.minDistance)),n=Math.cos(e)*s,h=this.fixedBehind?0:i;this.offset.x=Math.sin(-h)*n,this.offset.y=Math.sin(e)*s+this.offsetY,this.offset.z=Math.cos(-h)*-n,this.fixedBehind&&this.offset.add(this.lookAtOffset),this.updateCameraPosition(t)}checkForCollision(t,o){const e=g.subVectors(this.camera.position,t),i=e.length();if(i<.001)return;e.divideScalar(i);const s=this.physicsSystem.sphereCast(t,this.collisionSphereRadius,e,i,void 0,{excludeActor:this.actor,excludeTriggers:!0,collisionFilter:-2}),n=s.hasHit?Math.max(this.minDistance,s.distance-.05):i;if(!this.hasCollisionRestriction||n<=this.restrictedDistance)this.restrictedDistance=n,this.hasCollisionRestriction=!0;else{const t=1-Math.exp(-this.bounceBackSpeed*o);this.restrictedDistance=r.lerp(this.restrictedDistance,n,t)}this.camera.position.copy(t).addScaledVector(e,Math.min(i,this.restrictedDistance))}getLookAtPosition(){const t=k;return t.set(0,0,0),t.y=this.height,this.fixedBehind&&t.add(this.lookAtOffset),t.applyMatrix4(this.actor.object.matrixWorld),t}updateCameraPosition(t){this.actor.object.updateWorldMatrix(!0,!1),this.fixedBehind?(v.position.set(this.offset.x,this.offset.y,this.offset.z),v.rotation.set(0,0,0),v.scale.set(1,1,1),v.applyMatrix4(this.actor.object.matrix)):v.position.copy(this.actor.position).add(this.offset);const o=y.easeInOutCubic(1-this.blendDurationLeft);if(this.blendDurationLeft>0){const t=this.getLookAtPosition();this.prevLookAt.lerp(t,o),this.camera.lookAt(this.prevLookAt),this.camera.position.lerp(v.position,o),this.smoothedLookAt.copy(this.prevLookAt),this.previousTargetLookAt.copy(t),this.hasSmoothedLookAt=!0}else{const o=this.getLookAtPosition();if(this.smoothCamera){const e=1-Math.exp(-this.smoothSpeed*t),i=Math.max(0,this.teleportSnapDistance);!this.hasSmoothedLookAt||this.previousTargetLookAt.distanceToSquared(o)>i*i?this.smoothedLookAt.copy(o):this.smoothedLookAt.lerp(o,e)}else this.smoothedLookAt.copy(o);this.previousTargetLookAt.copy(o),this.hasSmoothedLookAt=!0,L.subVectors(v.position,o),this.camera.position.copy(this.smoothedLookAt).add(L),this.camera.lookAt(this.smoothedLookAt),this.prevLookAt.copy(this.smoothedLookAt)}this.collision&&(this.checkForCollision(this.prevLookAt,t),this.camera.lookAt(this.prevLookAt)),this.applyTemporaryControl(t)}applyTemporaryControl(t){if(!this.temporaryControlActive)return;this.temporaryControlTargetWeight>this.temporaryControlWeight?this.temporaryControlWeight=0===this.temporaryControlBlendInDuration?1:Math.min(1,this.temporaryControlWeight+t/this.temporaryControlBlendInDuration):this.temporaryControlTargetWeight<this.temporaryControlWeight&&(this.temporaryControlWeight=0===this.temporaryControlBlendOutDuration?0:Math.max(0,this.temporaryControlWeight-t/this.temporaryControlBlendOutDuration));const o=y.easeInOutCubic(this.temporaryControlWeight);this.temporaryControlPositionEnabled&&this.camera.position.lerp(this.getTemporaryControlPosition(),o),x.position.copy(this.camera.position),x.up.copy(this.camera.up),x.lookAt(this.temporaryControlLookAt),this.camera.quaternion.slerp(x.quaternion,o);const e=this.temporaryControlFieldOfView??this.temporaryControlBaseFieldOfView,i=r.lerp(this.temporaryControlBaseFieldOfView,e,o);this.camera.fov!==i&&(this.camera.fov=i,this.camera.updateProjectionMatrix()),0===this.temporaryControlTargetWeight&&0===this.temporaryControlWeight&&(this.temporaryControlActive=!1)}getTemporaryControlPosition(){if(!this.collision)return this.temporaryControlPosition;A.subVectors(this.temporaryControlPosition,this.temporaryControlLookAt);const t=A.length();if(t<.001)return this.temporaryControlPosition;A.divideScalar(t);const o=this.physicsSystem.sphereCast(this.temporaryControlLookAt,this.collisionSphereRadius,A,t,void 0,{excludeActor:this.actor,excludeTriggers:!0,collisionFilter:-2});return!o.hasHit||o.distance>=t?this.temporaryControlPosition:w.copy(this.temporaryControlLookAt).addScaledVector(A,Math.max(0,o.distance-.05))}};t([m(),o("design:type",Number)],C.prototype,"near",void 0),t([m(),o("design:type",Number)],C.prototype,"far",void 0),t([m(),o("design:type",Number)],C.prototype,"viewAngle",void 0),t([m(),o("design:type",Boolean)],C.prototype,"collision",void 0),t([m(),o("design:type",Number)],C.prototype,"collisionSphereRadius",void 0),t([m(),o("design:type",Boolean)],C.prototype,"smoothCamera",void 0),t([m(),o("design:type",Number)],C.prototype,"smoothSpeed",void 0),t([m(),o("design:type",Number)],C.prototype,"teleportSnapDistance",void 0),C=t([i(),o("design:paramtypes",[])],C);export{C as ThirdPersonCameraComponent};const v=new h,k=new s,L=new s,g=new s,A=new s,w=new s,x=new n;export class ThirdPartyCameraComponent extends C{}/*
1
+ import{__decorate as t,__metadata as o}from"tslib";import{ActorComponent as e,Component as i}from"../component.js";import{Vector3 as s,MathUtils as r,PerspectiveCamera as n,Object3D as h}from"three";import{ViewController as a}from"../../services/render.js";import{DecimalInput as l,RestrictedRotationInput as c}from"../../input/index.js";import{PhysicsSystem as p}from"../../services/physics/physics-system.js";import{Parameter as m}from"../../../shader/parameter.js";import{World as d}from"../../services/world.js";import{inject as u}from"../../inject.js";import{ease as y}from"@hology/nebula";const f=void 0!==window&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);let C=class extends e{constructor(){super(),this.viewController=u(a),this.physicsSystem=u(p),this.aspect=this.viewController.htmlElement.clientWidth/this.viewController.htmlElement.clientHeight,this.near=.1,this.far=500,this.viewAngle=f?30:45,this.collision=!0,this.collisionSphereRadius=.25,this.smoothCamera=!1,this.smoothSpeed=10,this.teleportSnapDistance=5,this.camera=new n(this.viewAngle,this.aspect,this.near,this.far),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetY=2,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=3,this.restrictedDistance=0,this.hasCollisionRestriction=!1,this.rotationInput=new c(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new l(1,0,1),this.offset=new s,this.lookAtOffset=new s(this.offsetX,0,this.offsetZ),this.fixedBehind=!0,this.world=u(d),this.activated=!1,this.isMouseLocked=!1,this.prevFixedBehind=!1,this.blendDurationLeft=0,this.pointerEventsRegistered=!1,this.temporaryControlActive=!1,this.temporaryControlWeight=0,this.temporaryControlTargetWeight=0,this.temporaryControlBlendInDuration=.5,this.temporaryControlBlendOutDuration=.5,this.temporaryControlPositionEnabled=!1,this.temporaryControlBaseFieldOfView=this.camera.fov,this.temporaryControlFieldOfView=null,this.temporaryControlPosition=new s,this.temporaryControlLookAt=new s,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||"mouse"!==t.pointerType||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.element.style.cursor=this.isMouseLocked?"none":"default",this.isMouseLocked||(this.pointerLockInactivatedAt=performance.now())},this.prevLookAt=new s,this.smoothedLookAt=new s,this.previousTargetLookAt=new s,this.hasSmoothedLookAt=!1,this.smoothedRotX=0,this.smoothedRotY=0,this.smoothZoom=0}async onInit(){this.prevFixedBehind=this.fixedBehind,this.world.scene.add(this.camera),this.rotationInput.rotation.copy(this.actor.rotation),this.smoothedRotX=this.rotationInput.rotation.x,this.smoothedRotY=this.rotationInput.rotation.y,this.hasCollisionRestriction=!1,this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.smoothZoom=this.zoomInput.value,this.autoActivate&&this.activate(),this.disposed.subscribe(()=>{this.unregisterPointerEvents()})}activate(){this.activated=!0,this.hasSmoothedLookAt=!1,this.viewController.setCamera(this.camera),this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.registerPointerEvents()}deactivate(){this.activated=!1,this.isMouseLocked=!1,this.unregisterPointerEvents()}setTemporaryControl(t,o,e={}){this.temporaryControlPosition.copy(t),this.temporaryControlLookAt.copy(o),this.temporaryControlPositionEnabled=!0,this.activateTemporaryControl(e)}setTemporaryLookAt(t,o={}){this.temporaryControlLookAt.copy(t),this.temporaryControlPositionEnabled=!1,this.activateTemporaryControl(o)}activateTemporaryControl(t){this.temporaryControlActive||(this.temporaryControlBaseFieldOfView=this.camera.fov),this.temporaryControlFieldOfView=null==t.fieldOfView?null:r.clamp(t.fieldOfView,1,179),null!=t.blendInDuration&&(this.temporaryControlBlendInDuration=Math.max(0,t.blendInDuration)),null!=t.blendOutDuration&&(this.temporaryControlBlendOutDuration=Math.max(0,t.blendOutDuration)),this.temporaryControlActive=!0,this.temporaryControlTargetWeight=1}clearTemporaryControl(t){this.temporaryControlActive&&(null!=t&&(this.temporaryControlBlendOutDuration=Math.max(0,t)),this.temporaryControlTargetWeight=0)}registerPointerEvents(){if(this.pointerEventsRegistered||null==document.body.requestPointerLock)return;const t=this.element;t.addEventListener("pointerdown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!0}unregisterPointerEvents(){if(!this.pointerEventsRegistered)return;const t=this.element;t.removeEventListener("pointerdown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!1}onLateUpdate(t){this.activated&&this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor({ignoreRecentUnlock:t=!1}={}){const o=!1!==navigator.pointerLockRequiresCooldown;!t&&o&&null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||this.requestPointerLock()}requestPointerLock(){const t=this.element.getElementsByTagName("canvas")[0],o=null!=t?.requestPointerLock?t:null!=this.element.requestPointerLock?this.element:null;if(null!=o)try{const t=o.requestPointerLock({unadjustedMovement:!0});t?.catch(()=>this.onPointerLockChange())}catch{this.onPointerLockChange()}else this.onPointerLockChange()}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",null==document.pointerLockElement&&null==document.mozPointerLockElement||window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.fixedBehind!==this.prevFixedBehind?(this.blendDurationLeft=1,this.prevFixedBehind=this.fixedBehind):this.blendDurationLeft>0&&(this.blendDurationLeft-=t);let o=this.zoomInput.value,e=this.rotationInput.rotation.x,i=this.rotationInput.rotation.y;if(this.smoothCamera){const s=1-Math.exp(-this.smoothSpeed*t*2);this.smoothedRotX=r.lerp(this.smoothedRotX,e,s),this.smoothedRotY=r.lerp(this.smoothedRotY,i,s),e=this.smoothedRotX,i=this.smoothedRotY,this.smoothZoom=r.lerp(this.smoothZoom,o,.4*s),o=this.smoothZoom}else this.smoothedRotX=e,this.smoothedRotY=i;const s=r.clamp(this.distance,this.minDistance,Math.max(this.distance*o,this.minDistance)),n=Math.cos(e)*s,h=this.fixedBehind?0:i;this.offset.x=Math.sin(-h)*n,this.offset.y=Math.sin(e)*s+this.offsetY,this.offset.z=Math.cos(-h)*-n,this.fixedBehind&&this.offset.add(this.lookAtOffset),this.updateCameraPosition(t)}checkForCollision(t,o){const e=g.subVectors(this.camera.position,t),i=e.length();if(i<.001)return;e.divideScalar(i);const s=this.physicsSystem.sphereCast(t,this.collisionSphereRadius,e,i,void 0,{excludeActor:this.actor,excludeTriggers:!0,collisionFilter:-2}),n=s.hasHit?Math.max(this.minDistance,s.distance-.05):i;if(!this.hasCollisionRestriction||n<=this.restrictedDistance)this.restrictedDistance=n,this.hasCollisionRestriction=!0;else{const t=1-Math.exp(-this.bounceBackSpeed*o);this.restrictedDistance=r.lerp(this.restrictedDistance,n,t)}this.camera.position.copy(t).addScaledVector(e,Math.min(i,this.restrictedDistance))}getLookAtPosition(){const t=k;return t.set(0,0,0),t.y=this.height,this.fixedBehind&&t.add(this.lookAtOffset),t.applyMatrix4(this.actor.object.matrixWorld),t}updateCameraPosition(t){this.actor.object.updateWorldMatrix(!0,!1),this.fixedBehind?(v.position.set(this.offset.x,this.offset.y,this.offset.z),v.rotation.set(0,0,0),v.scale.set(1,1,1),v.applyMatrix4(this.actor.object.matrix)):v.position.copy(this.actor.position).add(this.offset);const o=y.easeInOutCubic(1-this.blendDurationLeft);if(this.blendDurationLeft>0){const t=this.getLookAtPosition();this.prevLookAt.lerp(t,o),this.camera.lookAt(this.prevLookAt),this.camera.position.lerp(v.position,o),this.smoothedLookAt.copy(this.prevLookAt),this.previousTargetLookAt.copy(t),this.hasSmoothedLookAt=!0}else{const o=this.getLookAtPosition();if(this.smoothCamera){const e=1-Math.exp(-this.smoothSpeed*t),i=Math.max(0,this.teleportSnapDistance);!this.hasSmoothedLookAt||this.previousTargetLookAt.distanceToSquared(o)>i*i?this.smoothedLookAt.copy(o):this.smoothedLookAt.lerp(o,e)}else this.smoothedLookAt.copy(o);this.previousTargetLookAt.copy(o),this.hasSmoothedLookAt=!0,L.subVectors(v.position,o),this.camera.position.copy(this.smoothedLookAt).add(L),this.camera.lookAt(this.smoothedLookAt),this.prevLookAt.copy(this.smoothedLookAt)}this.collision&&(this.checkForCollision(this.prevLookAt,t),this.camera.lookAt(this.prevLookAt)),this.applyTemporaryControl(t)}applyTemporaryControl(t){if(!this.temporaryControlActive)return;this.temporaryControlTargetWeight>this.temporaryControlWeight?this.temporaryControlWeight=0===this.temporaryControlBlendInDuration?1:Math.min(1,this.temporaryControlWeight+t/this.temporaryControlBlendInDuration):this.temporaryControlTargetWeight<this.temporaryControlWeight&&(this.temporaryControlWeight=0===this.temporaryControlBlendOutDuration?0:Math.max(0,this.temporaryControlWeight-t/this.temporaryControlBlendOutDuration));const o=y.easeInOutCubic(this.temporaryControlWeight);this.temporaryControlPositionEnabled&&this.camera.position.lerp(this.getTemporaryControlPosition(),o),P.position.copy(this.camera.position),P.up.copy(this.camera.up),P.lookAt(this.temporaryControlLookAt),this.camera.quaternion.slerp(P.quaternion,o);const e=this.temporaryControlFieldOfView??this.temporaryControlBaseFieldOfView,i=r.lerp(this.temporaryControlBaseFieldOfView,e,o);this.camera.fov!==i&&(this.camera.fov=i,this.camera.updateProjectionMatrix()),0===this.temporaryControlTargetWeight&&0===this.temporaryControlWeight&&(this.temporaryControlActive=!1)}getTemporaryControlPosition(){if(!this.collision)return this.temporaryControlPosition;A.subVectors(this.temporaryControlPosition,this.temporaryControlLookAt);const t=A.length();if(t<.001)return this.temporaryControlPosition;A.divideScalar(t);const o=this.physicsSystem.sphereCast(this.temporaryControlLookAt,this.collisionSphereRadius,A,t,void 0,{excludeActor:this.actor,excludeTriggers:!0,collisionFilter:-2});return!o.hasHit||o.distance>=t?this.temporaryControlPosition:w.copy(this.temporaryControlLookAt).addScaledVector(A,Math.max(0,o.distance-.05))}};t([m(),o("design:type",Number)],C.prototype,"near",void 0),t([m(),o("design:type",Number)],C.prototype,"far",void 0),t([m(),o("design:type",Number)],C.prototype,"viewAngle",void 0),t([m(),o("design:type",Boolean)],C.prototype,"collision",void 0),t([m(),o("design:type",Number)],C.prototype,"collisionSphereRadius",void 0),t([m(),o("design:type",Boolean)],C.prototype,"smoothCamera",void 0),t([m(),o("design:type",Number)],C.prototype,"smoothSpeed",void 0),t([m(),o("design:type",Number)],C.prototype,"teleportSnapDistance",void 0),C=t([i(),o("design:paramtypes",[])],C);export{C as ThirdPersonCameraComponent};const v=new h,k=new s,L=new s,g=new s,A=new s,w=new s,P=new n;export class ThirdPartyCameraComponent extends C{}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{NavMesh as t,NavMeshParams as e,Raw as i,UnsignedCharArray as s,recastConfigDefaults as o,statusToReadableString as r}from"recast-navigation";import*as n from"three";import{buildConfig as a,buildTile as h}from"./build-tile.js";import{Subject as l}from"rxjs";import{executeTask as d,hasWorkerBuilder as u}from"../../worker/index.js";import{hasSharedArrayBufferSupport as c}from"../../utils/buffer.js";export const MAX_NAV_MESH_WORKERS=4;export const getTileBounds=(t,e,i,s,o)=>[[t.x+i*o,t.y,t.z+s*o],[t.x+(i+1)*o,e.y,t.z+(s+1)*o]];export class DynamicTiledNavMesh{constructor(i){this.navMeshVersion=0,this.onNavMeshUpdate=new l,this.abortController=new AbortController;const s=i.navMeshBounds.min,r=i.navMeshBounds.max,n=[s.toArray(),r.toArray()],h=i.navMeshBounds.min;this.navMeshBoundsMin=s,this.navMeshBoundsMax=r,this.navMeshBounds=n,this.navMeshOrigin=h,this.cacheId=i.cacheId,this.workerLimit=Math.min(4,Math.max(0,i.workers));const d={...o,...i.recastConfig};this.recastConfig=d;const u=new t,{tileWidth:c,tileHeight:M,tcs:m,maxPolysPerTile:v}=a({recastConfig:d,navMeshBounds:n});this.tileWidth=c,this.tileHeight=M,this.tcs=m;const f=e.create({orig:h,tileWidth:d.tileSize*d.cs,tileHeight:d.tileSize*d.cs,maxTiles:i.maxTiles,maxPolys:v});u.initTiled(f),this.navMesh=u}onResult(t){if(t.data.error)return void console.error(t.data.error);const{tileX:e,tileY:o,navMeshData:n}=t.data;if(this.navMesh.removeTile(this.navMesh.getTileRefAt(e,o,0)),null==n)return this.navMeshVersion++,void this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]]);const a=new s;a.copy(n);const h=this.navMesh.addTile(a,i.Module.DT_TILE_FREE_DATA,0);i.Detour.statusFailed(h.status)&&(console.error(i.Module.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${e}, ty: ${o},status: ${r(h.status)} (${h.status})`),a.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]])}buildTile(t,e,[i,s],o=!1,r=[]){const n=c&&t.buffer instanceof window.SharedArrayBuffer,a=n?t:new Float32Array(t),l=n?e:new Uint32Array(e),[v,f]=getTileBounds(this.navMeshBoundsMin,this.navMeshBoundsMax,i,s,this.tcs),g={tileX:i,tileY:s,tileBoundsMin:v,tileBoundsMax:f,recastConfig:this.recastConfig,navMeshBounds:this.navMeshBounds,keepIntermediates:!1,positions:a,indices:l,areaModifiers:r};return this.workerLimit>0&&u()?d("navmesh.buildTile",g,{transfer:n?void 0:[a.buffer,l.buffer],signal:this.abortController.signal,priority:"background"}).then(t=>this.onResult({data:t})).catch(t=>{"AbortError"!==t?.name&&console.error("Navmesh worker failed",t)}):new Promise(t=>{requestIdleCallback(()=>{const e=this.cacheId+JSON.stringify({tileX:g.tileX,tileY:g.tileY,areaModifiers:g.areaModifiers});if(o){const i=localStorage.getItem(e);if(null!=i){const e=m(i);return this.onResult({data:{tileX:g.tileX,tileY:g.tileY,navMeshData:e}}),void t({})}}else localStorage.removeItem(e);const i=h(g);if(!i.success)return console.error("error"in i?i.error:"Unknown navmesh tile build error"),void t(i);if(!i.data)return localStorage.removeItem(e),this.onResult({data:{tileX:g.tileX,tileY:g.tileY}}),void t(i);const s=i.data.toTypedArray();localStorage.setItem(e,M(s)),this.onResult({data:{tileX:g.tileX,tileY:g.tileY,navMeshData:s}}),t(i)})})}buildAllTiles(t,e){const{tileWidth:i,tileHeight:s}=this;for(let o=0;o<s;o++)for(let s=0;s<i;s++)this.buildTile(t,e,[s,o])}getTileForWorldPosition(t){return[Math.floor((t.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((t.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(t){if(!t.intersectsBox(new n.Box3(this.navMeshBoundsMin,this.navMeshBoundsMax)))return[];const e=this.getTileForWorldPosition(t.min),i=this.getTileForWorldPosition(t.max);e[0]=Math.max(0,Math.min(this.tileWidth-1,e[0])),e[1]=Math.max(0,Math.min(this.tileHeight-1,e[1])),i[0]=Math.max(0,Math.min(this.tileWidth-1,i[0])),i[1]=Math.max(0,Math.min(this.tileHeight-1,i[1]));const s=[];for(let t=e[1];t<=i[1];t++)for(let o=e[0];o<=i[0];o++)s.push([o,t]);return s}destroy(){this.abortController.abort(),this.navMesh.destroy(),this.onNavMeshUpdate.complete()}}const M=function(t){return btoa(String.fromCharCode(...t))},m=function(t){if(!t)return null;const e=atob(t),i=e.length,s=new Uint8Array(i);for(let t=0;t<i;t++)s[t]=e.charCodeAt(t);return s};/*
1
+ import{NavMesh as t,NavMeshParams as e,Raw as i,UnsignedCharArray as s,recastConfigDefaults as o,statusToReadableString as r}from"recast-navigation";import*as n from"three";import{buildConfig as a,buildTile as h}from"./build-tile.js";import{Subject as l}from"rxjs";import{executeTask as d,hasWorkerBuilder as u}from"../../worker/index.js";import{hasSharedArrayBufferSupport as c}from"../../utils/buffer.js";export const MAX_NAV_MESH_WORKERS=4;export const getTileBounds=(t,e,i,s,o)=>[[t.x+i*o,t.y,t.z+s*o],[t.x+(i+1)*o,e.y,t.z+(s+1)*o]];export class DynamicTiledNavMesh{constructor(i){this.navMeshVersion=0,this.onNavMeshUpdate=new l,this.abortController=new AbortController;const s=i.navMeshBounds.min,r=i.navMeshBounds.max,n=[s.toArray(),r.toArray()],h=i.navMeshBounds.min;this.navMeshBoundsMin=s,this.navMeshBoundsMax=r,this.navMeshBounds=n,this.navMeshOrigin=h,this.cacheId=i.cacheId,this.workerLimit=Math.min(4,Math.max(0,i.workers));const d={...o,...i.recastConfig};this.recastConfig=d;const u=new t,{tileWidth:c,tileHeight:M,tcs:m,maxPolysPerTile:v}=a({recastConfig:d,navMeshBounds:n});this.tileWidth=c,this.tileHeight=M,this.tcs=m;const f=e.create({orig:h,tileWidth:d.tileSize*d.cs,tileHeight:d.tileSize*d.cs,maxTiles:i.maxTiles,maxPolys:v});u.initTiled(f),this.navMesh=u}onResult(t){if(t.data.error)return void console.error(t.data.error);const{tileX:e,tileY:o,navMeshData:n}=t.data;if(this.navMesh.removeTile(this.navMesh.getTileRefAt(e,o,0)),null==n)return this.navMeshVersion++,void this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]]);const a=new s;a.copy(n);const h=this.navMesh.addTile(a,i.Module.DT_TILE_FREE_DATA,0);i.Detour.statusFailed(h.status)&&(console.error(i.Module.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${e}, ty: ${o},status: ${r(h.status)} (${h.status})`),a.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]])}buildTile(t,e,[i,s],o=!1,r=[]){const n=c&&t.buffer instanceof window.SharedArrayBuffer,a=n?t:new Float32Array(t),l=n?e:new Uint32Array(e),[v,f]=getTileBounds(this.navMeshBoundsMin,this.navMeshBoundsMax,i,s,this.tcs),g={tileX:i,tileY:s,tileBoundsMin:v,tileBoundsMax:f,recastConfig:this.recastConfig,navMeshBounds:this.navMeshBounds,keepIntermediates:!1,positions:a,indices:l,areaModifiers:r};return this.workerLimit>0&&u()?d("navmesh.buildTile",g,{transfer:n?void 0:[a.buffer,l.buffer],signal:this.abortController.signal,priority:"background"}).then(t=>this.onResult({data:t})).catch(t=>{"AbortError"!==t?.name&&console.error("Navmesh worker failed",t)}):new Promise(t=>{(globalThis.requestIdleCallback??(t=>setTimeout(t,0)))(()=>{const e=this.cacheId+JSON.stringify({tileX:g.tileX,tileY:g.tileY,areaModifiers:g.areaModifiers});if(o){const i=localStorage.getItem(e);if(null!=i){const e=m(i);return this.onResult({data:{tileX:g.tileX,tileY:g.tileY,navMeshData:e}}),void t({})}}else localStorage.removeItem(e);const i=h(g);if(!i.success)return console.error("error"in i?i.error:"Unknown navmesh tile build error"),void t(i);if(!i.data)return localStorage.removeItem(e),this.onResult({data:{tileX:g.tileX,tileY:g.tileY}}),void t(i);const s=i.data.toTypedArray();localStorage.setItem(e,M(s)),this.onResult({data:{tileX:g.tileX,tileY:g.tileY,navMeshData:s}}),t(i)})})}buildAllTiles(t,e){const{tileWidth:i,tileHeight:s}=this;for(let o=0;o<s;o++)for(let s=0;s<i;s++)this.buildTile(t,e,[s,o])}getTileForWorldPosition(t){return[Math.floor((t.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((t.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(t){if(!t.intersectsBox(new n.Box3(this.navMeshBoundsMin,this.navMeshBoundsMax)))return[];const e=this.getTileForWorldPosition(t.min),i=this.getTileForWorldPosition(t.max);e[0]=Math.max(0,Math.min(this.tileWidth-1,e[0])),e[1]=Math.max(0,Math.min(this.tileHeight-1,e[1])),i[0]=Math.max(0,Math.min(this.tileWidth-1,i[0])),i[1]=Math.max(0,Math.min(this.tileHeight-1,i[1]));const s=[];for(let t=e[1];t<=i[1];t++)for(let o=e[0];o<=i[0];o++)s.push([o,t]);return s}destroy(){this.abortController.abort(),this.navMesh.destroy(),this.onNavMeshUpdate.complete()}}const M=function(t){return btoa(String.fromCharCode(...t))},m=function(t){if(!t)return null;const e=atob(t),i=e.length,s=new Uint8Array(i);for(let t=0;t<i;t++)s[t]=e.charCodeAt(t);return s};/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -12,6 +12,10 @@ export type InitiateGameConfig = {
12
12
  element: HTMLElement;
13
13
  sceneName: string;
14
14
  dataDir: string;
15
+ /** Bypasses callback-based Three file loaders for runtimes with a partial DOM implementation. */
16
+ directAssetFileLoading?: boolean;
17
+ /** Target-specific location of the generated hology_data.json bundle. */
18
+ runtimeDataUrl?: string | URL;
15
19
  shaders: {
16
20
  [name: string]: ShaderType;
17
21
  };
@@ -1,4 +1,4 @@
1
- import e from"typedi";import{loadScene as t}from"../scene/bootstrap.js";import{ActorFactory as n}from"./actors/factory.js";import{World as s}from"./services/world.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{ViewController as r}from"./services/render.js";import{RenderingView as i}from"../rendering.js";import{PhysicsSystem as a}from"./services/physics/physics-system.js";import{MeshComponent as c}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as d}from"./actors/builtin/components/index.js";import{activeContainerInstance as m}from"./actors/internal/container-map.js";import{InputService as l}from"./input/index.js";import{RuntimeAssetsService as p}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as u}from"../scene/asset-resource-loader.js";import{AssetLoader as h}from"./services/asset-loader.js";import{polyfillClient as g}from"./polyfill.js";import{Subject as f}from"rxjs";import{PointerEvents as w}from"./services/pointer-events.js";import{RuntimeBundledBackendService as b}from"../scene/runtime-bundled-backend-service.js";import{Scene as v}from"three";import{ShaderProvider as S}from"./services/shader-provider.js";import{SceneDataService as j}from"../scene/scene-data-service.js";import{NetMode as x}from"./net/net-session.js";import{AssetsProvider as y}from"../scene/assets-provider.js";import{GpuVfxWorldService as I}from"../effects/vfx/gpu-vfx-world-service.js";export function initiateGame(f,w){if(g(),0!=w.element.childNodes.length)return console.error("Can not initialize the game with a non-empty html element"),null;e.has(r);const P=e.of("default"),D=new HologyRuntime(P),G=new n(P,{inEditor:!1});var k;G.classes=w.actors,e.set(n,G),k=w.element,Object.assign(k.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"});const W=new i(w.element,{backend:w.rendering?.backend??"webgpu-experimental",enableXR:!0===w.xr?.enabled,maxPixelRatio:w.rendering?.maxPixelRatio,resolutionScale:w.rendering?.resolutionScale,dynamicResolution:w.rendering?.dynamicResolution,upscaling:w.rendering?.upscaling,webgpuPostProcessing:w.rendering?.webgpuPostProcessing,webgpuDirectionalShadows:w.rendering?.webgpuDirectionalShadows,webgpuVfx:w.rendering?.webgpuVfx??"auto",msaa:w.rendering?.msaa,fpsCap:w.rendering?.fpsCap,depthPrepass:{enabled:!0===w.rendering?.depthPrepass?.enabled},bloom:{enabled:!1!==w?.rendering?.bloom?.enabled},reflection:{enabled:!1!==w?.rendering?.reflection?.enabled},occlusionCulling:{enabled:!1!==w?.rendering?.occlusionCulling?.enabled},shadows:{cascadeUpdateIntervals:[22,40,60,120]}});W.renderer.shadowMap.enabled=w.rendering?.shadows?.enabled??!0,W.renderer.shadowMap.autoUpdate=w.rendering?.shadows?.autoUpdate??!0,W.renderer.debug.checkShaderErrors=!1,e.set(i,W);const E=new r(W);e.set(r,E);const R=new b,A=new p(R),C=new u;C.setDataDir(w.dataDir),C.initKtx2(W.renderer);const M=Object.entries(w.shaders).map(([e,t])=>({name:e,type:t})),z=Object.entries(w.actors).map(([e,t])=>({name:e,type:t})),F={...d,...w.components??{}},O=Object.entries(F).map(([e,t])=>({name:e,type:t})),U=new S(M);e.set(S,U);const q=new h(C,A,M);e.set(y,A),e.set(u,C),e.set(h,q);const H=new v,N=new o(H,new j,A,C,W,M,z,G,O);N.inEditor=!1,N.netMode=w.multi?.session?.mode??x.none,e.set(o,N);const T=e.get(s);return e.set(s,T),T.materializer=N,(async()=>{const n=e.get(a);if(await n.start(),D.isShutdown)return;if(await R.preloadData(),D.isShutdown)return;if(T.scene=H,null!=w.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=P.get(e);t.session=w.multi.session,t.start(),D.shutdownStarted.subscribe(()=>t.stop())}const{scene:s,actors:o,materializer:r}=await t(W,w.sceneName,w.dataDir,w.shaders,w.actors,F,G,R,A,C,{detailTier:w.detailTier,nodeMode:w.multi?.session?.mode??x.none});T.scene=s,n.scene=T.scene;for(const e of H.children)T.scene.add(e);if(D.isShutdown)return void W.stop();e.import([c]);for(const e of o)T.addActor(e);n.addFromScene(s),await T.startSceneEventGraphs(r),m.value=P,P.remove(f),P.set({id:f,type:f});const i=P.get(f);if(m.value=null,D.gameInstance=i,i instanceof GameInstance&&await i.onPreload(),D.isShutdown)return void W.stop();if(console.log("Start compile shaders"),console.time("compile shaders"),await W.compileAsync(),console.timeEnd("compile shaders"),"webgpu-experimental"===W.activeBackend?console.log("Finished compiling the experimental WebGPU scene."):console.log("Finished compile shaders. Programs: ",W.renderer.info.programs?.length??0),console.log("Start init scene textures"),console.time("init scene textures"),W.initTextures(),console.timeEnd("init scene textures"),"webgpu-experimental"===W.activeBackend){const e=P.get(I).beginPipelineWarmup();try{W.render(0),await(W.experimentalWebGpuDevice?.queue.onSubmittedWorkDone())}finally{e()}W.render(0),await(W.experimentalWebGpuDevice?.queue.onSubmittedWorkDone()),await new Promise(e=>requestAnimationFrame(()=>e()))}const d=P.get(l);W.loop(e=>{d.update(e)}),D.status=5,D.shutdownStarted.subscribe(()=>{C.disposeAll()}),i instanceof GameInstance&&await i.onStart(),D._resolver(!0)})(),D}export class GameInstance{onPreload(){}onStart(){}onShutdown(){}}export function createHologyScene(){}export class HologyRuntime{constructor(e){this.containerInstance=e,this.status=0,this.isShutdown=!1,this.shutdownStarted=new f,this.ready=new Promise(e=>{this._resolver=e})}getWorld(){return this.containerInstance.get(s)}getService(e){return this.containerInstance.get(e)}shutdown(){this.isShutdown=!0;const e=this.shutdownStarted;e.next(),e.complete(),this.gameInstance instanceof GameInstance&&this.gameInstance.onShutdown(),this.containerInstance.get(l).stop();const t=this.containerInstance.get(i);t?.stop();const n=this.getWorld();n.stopSceneEventGraphs();const s=this.containerInstance.get(r);s.setMuted(!0),s.dispose();for(const e of[...n.actors])n.removeActor(e);this.containerInstance.get(a).stop(),this.containerInstance.get(o).dispose();const c=this.containerInstance.get(y);c instanceof p&&c.dispose(),this.containerInstance.get(w).stop(),this.containerInstance.reset(),this.shutdownStarted.complete()}}/*
1
+ import e from"typedi";import{loadScene as t}from"../scene/bootstrap.js";import{ActorFactory as n}from"./actors/factory.js";import{World as s}from"./services/world.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{ViewController as i}from"./services/render.js";import{RenderingView as r}from"../rendering.js";import{PhysicsSystem as a}from"./services/physics/physics-system.js";import{MeshComponent as c}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as d}from"./actors/builtin/components/index.js";import{activeContainerInstance as l}from"./actors/internal/container-map.js";import{InputService as m}from"./input/index.js";import{RuntimeAssetsService as p}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as u}from"../scene/asset-resource-loader.js";import{AssetLoader as g}from"./services/asset-loader.js";import{polyfillClient as h}from"./polyfill.js";import{Subject as f}from"rxjs";import{PointerEvents as w}from"./services/pointer-events.js";import{RuntimeBundledBackendService as b}from"../scene/runtime-bundled-backend-service.js";import{Scene as v}from"three";import{ShaderProvider as y}from"./services/shader-provider.js";import{SceneDataService as S}from"../scene/scene-data-service.js";import{NetMode as j}from"./net/net-session.js";import{AssetsProvider as x}from"../scene/assets-provider.js";import{GpuVfxWorldService as I}from"../effects/vfx/gpu-vfx-world-service.js";export function initiateGame(f,w){if(h(),0!=w.element.childNodes.length)return console.error("Can not initialize the game with a non-empty html element"),null;e.has(i);const P=e.of("default"),D=new HologyRuntime(P),G=new n(P,{inEditor:!1});var k;G.classes=w.actors,e.set(n,G),k=w.element,Object.assign(k.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"});const W=new r(w.element,{backend:w.rendering?.backend??"webgpu",enableXR:!0===w.xr?.enabled,maxPixelRatio:w.rendering?.maxPixelRatio,resolutionScale:w.rendering?.resolutionScale,dynamicResolution:w.rendering?.dynamicResolution,upscaling:w.rendering?.upscaling,webgpuPostProcessing:w.rendering?.webgpuPostProcessing,webgpuDirectionalShadows:w.rendering?.webgpuDirectionalShadows,webgpuVfx:w.rendering?.webgpuVfx??"auto",msaa:w.rendering?.msaa,fpsCap:w.rendering?.fpsCap,depthPrepass:{enabled:!0===w.rendering?.depthPrepass?.enabled},bloom:{enabled:!1!==w?.rendering?.bloom?.enabled},reflection:{enabled:!1!==w?.rendering?.reflection?.enabled},occlusionCulling:{enabled:!1!==w?.rendering?.occlusionCulling?.enabled},shadows:{enabled:w.rendering?.shadows?.enabled??!0,autoUpdate:w.rendering?.shadows?.autoUpdate??!0,cascadeUpdateIntervals:[22,40,60,120]}});e.set(r,W);const F=new i(W);e.set(i,F);const H=new b(w.runtimeDataUrl),R=new p(H),z=new u;z.setDataDir(w.dataDir),z.setDirectFileLoading(!0===w.directAssetFileLoading),"webgpu"===W.requestedBackend?z.initKtx2ForWebGpu():z.initKtx2(W.renderer);const A=Object.entries(w.shaders).map(([e,t])=>({name:e,type:t})),E=Object.entries(w.actors).map(([e,t])=>({name:e,type:t})),C={...d,...w.components??{}},U=Object.entries(C).map(([e,t])=>({name:e,type:t})),q=new y(A);e.set(y,q);const O=new g(z,R,A);e.set(x,R),e.set(u,z),e.set(g,O);const B=new v,L=new o(B,new S,R,z,W,A,E,G,U);L.inEditor=!1,L.netMode=w.multi?.session?.mode??j.none,e.set(o,L);const M=e.get(s);return e.set(s,M),M.materializer=L,(async()=>{const n=e.get(a);if(console.info("[Hology] Initializing physics."),await n.start(),console.info("[Hology] Physics initialized."),D.isShutdown)return;if(console.info("[Hology] Loading runtime data."),await H.preloadData(),console.info("[Hology] Runtime data loaded."),D.isShutdown)return;if(M.scene=B,null!=w.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=P.get(e);t.session=w.multi.session,t.start(),D.shutdownStarted.subscribe(()=>t.stop())}const{scene:s,actors:o,materializer:i}=await t(W,w.sceneName,w.dataDir,w.shaders,w.actors,C,G,H,R,z,{detailTier:w.detailTier,nodeMode:w.multi?.session?.mode??j.none});M.scene=s,n.scene=M.scene;for(const e of B.children)M.scene.add(e);if(D.isShutdown)return void W.stop();e.import([c]);for(const e of o)M.addActor(e);n.addFromScene(s),await M.startSceneEventGraphs(i),l.value=P,P.remove(f),P.set({id:f,type:f});const r=P.get(f);if(l.value=null,D.gameInstance=r,r instanceof GameInstance&&await r.onPreload(),D.isShutdown)return void W.stop();if(console.log("Start compile shaders"),console.time("compile shaders"),await W.compileAsync(),console.timeEnd("compile shaders"),"webgpu"===W.activeBackend?console.log("Finished compiling the experimental WebGPU scene."):console.log("Finished compile shaders. Programs: ",W.renderer.info.programs?.length??0),console.log("Start init scene textures"),console.time("init scene textures"),await W.initTexturesAsync(),console.timeEnd("init scene textures"),"webgpu"===W.activeBackend){const e=P.get(I).beginPipelineWarmup();try{W.render(0),await(W.experimentalWebGpuDevice?.queue.onSubmittedWorkDone())}finally{e()}W.render(0),await(W.experimentalWebGpuDevice?.queue.onSubmittedWorkDone()),await new Promise(e=>requestAnimationFrame(()=>e()))}const d=P.get(m);W.loop(e=>{d.update(e)}),D.status=5,D.shutdownStarted.subscribe(()=>{z.disposeAll()}),r instanceof GameInstance&&await r.onStart(),D._resolver(!0)})().catch(e=>{D.status=10,console.error("Failed to initialize Hology runtime.",e),e instanceof Error&&console.error(e.stack)}),D}export class GameInstance{onPreload(){}onStart(){}onShutdown(){}}export function createHologyScene(){}export class HologyRuntime{constructor(e){this.containerInstance=e,this.status=0,this.isShutdown=!1,this.shutdownStarted=new f,this.ready=new Promise(e=>{this._resolver=e})}getWorld(){return this.containerInstance.get(s)}getService(e){return this.containerInstance.get(e)}shutdown(){this.isShutdown=!0;const e=this.shutdownStarted;e.next(),e.complete(),this.gameInstance instanceof GameInstance&&this.gameInstance.onShutdown(),this.containerInstance.get(m).stop();const t=this.containerInstance.get(r);t?.stop();const n=this.getWorld();n.stopSceneEventGraphs();const s=this.containerInstance.get(i);s.setMuted(!0),s.dispose();for(const e of[...n.actors])n.removeActor(e);this.containerInstance.get(a).stop(),this.containerInstance.get(o).dispose();const c=this.containerInstance.get(x);c instanceof p&&c.dispose(),this.containerInstance.get(w).stop(),this.containerInstance.reset(),this.shutdownStarted.complete()}}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -7,7 +7,7 @@ import { BaseActor } from '../../gameplay/actors/actor.js';
7
7
  import { PostProcessVolume } from "@hology/core";
8
8
  import type { PostProcessEffect, PostProcessEffectOptions } from '../../rendering/post-process-effect.js';
9
9
  import type { PostProcessMaterialSource } from "../../shader/post-process-shader.js";
10
- import type { ExperimentalWebGpuRenderGraphExtension, RenderingBackend } from '../../rendering.js';
10
+ import type { ActiveRenderingBackend, ExperimentalWebGpuRenderGraphExtension } from '../../rendering.js';
11
11
  import type { VfxBackendPreference } from '../../effects/vfx/gpu-sprite-compiler.js';
12
12
  import { type CameraShakeRequest } from "./camera-shake.js";
13
13
  export type { CameraShakeRequest, CameraShakeSample, CameraShakeSettings, CameraShakeVector3, } from "./camera-shake.js";
@@ -44,15 +44,19 @@ export declare class ViewController {
44
44
  private readonly accumulatedCameraShakeSample;
45
45
  private readonly scratchCameraShakeSample;
46
46
  constructor(view: RenderingView);
47
- get activeBackend(): RenderingBackend;
48
- get requestedBackend(): RenderingBackend;
47
+ get activeBackend(): ActiveRenderingBackend | null;
48
+ get requestedBackend(): ActiveRenderingBackend;
49
49
  get vfxBackendPreference(): VfxBackendPreference;
50
50
  get webgpuVfxInstancesPerTemplate(): number;
51
51
  get webgpuVfxTemplateMemoryBudgetBytes(): number;
52
52
  get webgpuVfxWorldMemoryBudgetBytes(): number;
53
53
  /** @deprecated Retained for source compatibility; GPU VFX no longer performs timed eviction. */
54
54
  get webgpuVfxColdTemplateSeconds(): number;
55
+ get webGpuDevice(): GPUDevice | null;
56
+ /** @deprecated Use webGpuDevice. */
55
57
  get experimentalWebGpuDevice(): GPUDevice | null;
58
+ registerWebGpuRenderGraphExtension(extension: ExperimentalWebGpuRenderGraphExtension): () => void;
59
+ /** @deprecated Use registerWebGpuRenderGraphExtension. */
56
60
  registerExperimentalWebGpuRenderGraphExtension(extension: ExperimentalWebGpuRenderGraphExtension): () => void;
57
61
  private handleFrame;
58
62
  set timeScale(value: number);
@@ -68,6 +72,10 @@ export declare class ViewController {
68
72
  get fpsCap(): number | null;
69
73
  set showStats(value: boolean);
70
74
  get showStats(): boolean;
75
+ /** Enables renderer timing collection without requiring the HTML stats UI. */
76
+ setProfilingEnabled(enabled: boolean): void;
77
+ /** Returns the latest completed WebGPU frame profile when profiling is enabled. */
78
+ getLastFrameProfile(): import("@hology/webgpu-renderer").RendererFrameProfile;
71
79
  addPostProcessVolume(volume: PostProcessVolume): void;
72
80
  removePostProcessVolume(volume: PostProcessVolume): void;
73
81
  addPostProcessEffect(source: PostProcessMaterialSource, options?: PostProcessEffectOptions): PostProcessEffect;
@@ -1,4 +1,4 @@
1
- import{__decorate as e,__metadata as t}from"tslib";import{Service as a}from"typedi";import{Camera as i}from"three";import{RenderingView as r}from"../../rendering.js";import{BehaviorSubject as s,Subject as n,takeUntil as h}from"rxjs";import*as o from"three";import{GameTimeScheduler as m}from"./game-time-scheduler.js";import{createCameraShakeSample as l,resetCameraShakeSample as u,sampleCameraShake as c}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let d=class{constructor(e){this.view=e,this.tick=new n,this.lateTick=new n,this.audioListener=new o.AudioListener,this.pausedChanged=new s(!1),this.mutedChanged=new s(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new m,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=l(),this.scratchCameraShakeSample=l(),this.outlined=[],this.baseCamera=e.camera,this.sourceCamera=e.camera,e.onLoop(e=>{this.handleFrame(e)}),e.camera.add(this.audioListener),window.hology_view=this}get activeBackend(){return this.view.activeBackend}get requestedBackend(){return this.view.requestedBackend}get vfxBackendPreference(){return this.view.vfxBackendPreference}get webgpuVfxInstancesPerTemplate(){return this.view.webgpuVfxInstancesPerTemplate}get webgpuVfxTemplateMemoryBudgetBytes(){return this.view.webgpuVfxTemplateMemoryBudgetBytes}get webgpuVfxWorldMemoryBudgetBytes(){return this.view.webgpuVfxWorldMemoryBudgetBytes}get webgpuVfxColdTemplateSeconds(){return this.view.webgpuVfxColdTemplateSeconds}get experimentalWebGpuDevice(){return this.view.experimentalWebGpuDevice}registerExperimentalWebGpuRenderGraphExtension(e){return this.view.registerExperimentalWebGpuRenderGraphExtension(e)}handleFrame(e){let t=this._timeScale,a=0;this._hitStopRemaining>0?(this._hitStopRemaining-=1e3*e,this._hitStopRemaining<=0&&(this._hitStopRemaining=0),t=0):a=e*this._timeScale,this.advanceGameplayCameraShakes(a),this.tick.next(a),this.scheduler.update(1e3*a),this.lateTick.next(a),this.view.simulationTimeScale=t,this.refreshCameraPresentation()}set timeScale(e){this._timeScale=Math.max(0,e)}get timeScale(){return this._timeScale}applyHitStop(e){this._hitStopRemaining=Math.max(this._hitStopRemaining,e)}set fpsCap(e){this.view.fpsCap=e}get fpsCap(){return this.view.fpsCap}set showStats(e){this.view.showStats=e}get showStats(){return this.view.showStats}setLightVolume(e){this.view.lightVolume=e}getLightVolume(){return this.view.lightVolume}addPostProcessVolume(e){this.view.addPostProcessVolume(e)}removePostProcessVolume(e){this.view.removePostProcessVolume(e)}addPostProcessEffect(e,t){return this.view.addPostProcessEffect(e,t)}onUpdate(e){return null==e?this.tick:this.tick.pipe(h(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(h(e.disposed))}setCamera(e){const t=e instanceof i?e:e.camera.instance;this.baseCamera=t,0===this.cameraOverrides.length&&(this.sourceCamera=t,this.refreshCameraPresentation())}getCamera(){return this.view.camera}getSourceCamera(){return this.sourceCamera}getBaseCamera(){return this.baseCamera}applyCameraShake(e){const t=function(e){return{duration:Math.max(0,e.duration??0),attack:e.attack??0,decay:e.decay??0,frequency:e.frequency??24,positionAmplitude:e.positionAmplitude?[...e.positionAmplitude]:[0,0,0],rotationAmplitude:e.rotationAmplitude?[...e.rotationAmplitude]:[0,0,0],seed:e.seed}}(e);if(t.duration<=0)return{release:()=>{}};const a={id:++this.cameraShakeId,request:t,elapsedTime:0,seedOverride:t.seed};this.gameplayCameraShakes.push(a),this.refreshCameraPresentation();let i=!1;return{release:()=>{i||(i=!0,this.releaseGameplayCameraShake(a.id))}}}setCameraShakeContribution(e,t,a,i,r){if(a.duration<=0)return void this.removeCameraShakeContribution(e,t);let s=this.cameraShakeContributions.get(e);s||(s=new Map,this.cameraShakeContributions.set(e,s));const n=s.get(t);n?(n.request=a,n.elapsedTime=Math.max(0,i),n.seedOverride=r):s.set(t,{key:t,request:a,elapsedTime:Math.max(0,i),seedOverride:r}),this.refreshCameraPresentation()}removeCameraShakeContribution(e,t){const a=this.cameraShakeContributions.get(e);a?.delete(t)&&(0===a.size&&this.cameraShakeContributions.delete(e),this.refreshCameraPresentation())}clearCameraShakeContributionsForOwner(e){this.cameraShakeContributions.delete(e)&&this.refreshCameraPresentation()}pushCameraOverride(e,t,a=0){const i={id:++this.cameraOverrideId,camera:e,owner:t,priority:a};this.cameraOverrides.push(i),this.applyTopCameraOverride();let r=!1;return{release:()=>{r||(r=!0,this.releaseCameraOverrideEntry(i))}}}releaseCameraOverridesForOwner(e){const t=this.cameraOverrides.filter(t=>t.owner!==e);t.length!==this.cameraOverrides.length&&(this.cameraOverrides=t,this.applyTopCameraOverride())}releaseCameraOverrideEntry(e){const t=this.cameraOverrides.indexOf(e);-1!==t&&(this.cameraOverrides.splice(t,1),this.applyTopCameraOverride())}applyTopCameraOverride(){const e=this.getTopCameraOverride();this.sourceCamera=e?.camera??this.baseCamera,this.refreshCameraPresentation()}getTopCameraOverride(){let e;for(const t of this.cameraOverrides)(!e||t.priority>e.priority||t.priority===e.priority&&t.id>e.id)&&(e=t);return e}applyRenderedCamera(e){this.view.camera!==e&&this.view.setCamera(e),e.add(this.audioListener)}releaseGameplayCameraShake(e){const t=this.gameplayCameraShakes.findIndex(t=>t.id===e);-1!==t&&(this.gameplayCameraShakes.splice(t,1),this.refreshCameraPresentation())}advanceGameplayCameraShakes(e){if(!(e<=0||0===this.gameplayCameraShakes.length))for(let t=this.gameplayCameraShakes.length-1;t>=0;t--){const a=this.gameplayCameraShakes[t];a.elapsedTime+=e,a.elapsedTime>a.request.duration&&this.gameplayCameraShakes.splice(t,1)}}refreshCameraPresentation(){if(!this.hasActiveCameraShake())return void this.applyRenderedCamera(this.sourceCamera);const e=this.ensurePresentationCamera();this.copyCameraState(this.sourceCamera,e),this.accumulateCameraShakeSamples(),this.applyCameraShakeSample(e),this.applyRenderedCamera(e)}hasActiveCameraShake(){if(this.gameplayCameraShakes.length>0)return!0;for(const e of this.cameraShakeContributions.values())if(e.size>0)return!0;return!1}ensurePresentationCamera(){return this.presentationCamera||(this.presentationCamera=new o.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(v)),t.quaternion.copy(e.getWorldQuaternion(w)),t.scale.copy(e.getWorldScale(f)),t.layers.mask=e.layers.mask,e instanceof o.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect,t.zoom=e.zoom,t.focus=e.focus,t.filmGauge=e.filmGauge,t.filmOffset=e.filmOffset,t.view=null==e.view?null:{enabled:e.view.enabled,fullWidth:e.view.fullWidth,fullHeight:e.view.fullHeight,offsetX:e.view.offsetX,offsetY:e.view.offsetY,width:e.view.width,height:e.view.height},t.updateProjectionMatrix()):(t.projectionMatrix.copy(e.projectionMatrix),t.projectionMatrixInverse.copy(e.projectionMatrixInverse))}accumulateCameraShakeSamples(){u(this.accumulatedCameraShakeSample);for(let e=0;e<this.gameplayCameraShakes.length;e++)this.accumulateCameraShakeEntry(this.gameplayCameraShakes[e]);for(const e of this.cameraShakeContributions.values())for(const t of e.values())this.accumulateCameraShakeEntry(t)}accumulateCameraShakeEntry(e){const t=c(e.request,e.elapsedTime,this.scratchCameraShakeSample,e.seedOverride);if(t)for(let e=0;e<3;e++)this.accumulatedCameraShakeSample.position[e]+=t.position[e],this.accumulatedCameraShakeSample.rotation[e]+=t.rotation[e]}applyCameraShakeSample(e){k.copy(e.quaternion),y.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),y.applyQuaternion(k),e.position.add(y),x.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),O.setFromEuler(x),e.quaternion.copy(k).multiply(O),e.updateMatrixWorld(!0)}setMuted(e){this._muted=e,this.applyAudioGain(),this.mutedChanged.next(e)}getMuted(){return this._muted}set masterVolume(e){this._masterVolume=Math.min(Math.max(e,0),1),this.applyAudioGain()}get masterVolume(){return this._masterVolume}set cameraShakeIntensity(e){this._cameraShakeIntensity=Math.min(Math.max(e,0),1),this.refreshCameraPresentation()}get cameraShakeIntensity(){return this._cameraShakeIntensity}applyAudioGain(){this.audioListener.gain.gain.setValueAtTime(this._muted?0:this._masterVolume,this.audioListener.context.currentTime)}setOutlined(e){this.outlined.length=0;const t=this.outlined;for(let a=0;a<e.length;a++)t[a]=e[a];this.view.setSelectedObjects(t),this.view.setEnableOutlines(e.length>0)}getOutlined(){return this.outlined}addOutlined(e){this.outlined.includes(e)||(this.outlined.push(e),this.view.setSelectedObjects(this.outlined),this.view.setEnableOutlines(!0))}removeOutlined(e){const t=this.outlined.indexOf(e);-1!==t&&(this.outlined.splice(t,1),this.view.setSelectedObjects(this.outlined))}setOutlineColor(e){this.view.outlinePass?.visibleEdgeColor.copy(e)}getOutlineColor(){return this.view.outlinePass?.visibleEdgeColor}setOutlineThickness(e){this.view.outlinePass.edgeThickness=e}getOutlineThickness(){return this.view.outlinePass.edgeThickness}get htmlElement(){return this.view.container}getViewportSize(e=S){return this.view.getClientSize(e)}get paused(){return this.view.paused}set paused(e){e!=this.paused&&(e?this.pauseRendering():this.unpauseRendering())}pauseRendering(){this.view.paused=!0,this.pausedChanged.next(this.view.paused),this.scheduler.pause()}unpauseRendering(){this.view.paused=!1,this.pausedChanged.next(this.view.paused),this.scheduler.resume()}setInterval(e,t,a){return this.scheduler.setInterval(e,t,a)}clearInterval(e){this.scheduler.clearInterval(e)}dispose(){this.view.running&&this.view.stop(),this.scheduler.dispose(),this.cameraOverrides.length=0,this.gameplayCameraShakes.length=0,this.cameraShakeContributions.clear(),this.audioListener.removeFromParent(),this.tick.complete(),this.lateTick.complete(),this.paused=!0}createTimer(e){return this.scheduler.createTimer(e)}getScreenPosition(e,t=C,a=this.getViewportSize()){const i=this.getCamera();return p.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof o.PerspectiveCamera&&(g.setFromProjectionMatrix(p),!g.containsPoint(e))?null:(t.copy(e),t.project(i),t.x=(t.x+1)/2*a.x,t.y=(1-t.y)/2*a.y,t)}};d=e([a(),t("design:paramtypes",[r])],d);export{d as ViewController};const p=new o.Matrix4,C=new o.Vector3,S=new o.Vector2,g=new o.Frustum,v=new o.Vector3,f=new o.Vector3,w=new o.Quaternion,k=new o.Quaternion,y=new o.Vector3,x=new o.Euler(0,0,0,"XYZ"),O=new o.Quaternion;/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import{Service as a}from"typedi";import{Camera as i}from"three";import{RenderingView as r}from"../../rendering.js";import{BehaviorSubject as s,Subject as n,takeUntil as h}from"rxjs";import*as o from"three";import{GameTimeScheduler as m}from"./game-time-scheduler.js";import{createCameraShakeSample as l,resetCameraShakeSample as u,sampleCameraShake as c}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let d=class{constructor(e){this.view=e,this.tick=new n,this.lateTick=new n,this.audioListener=new o.AudioListener,this.pausedChanged=new s(!1),this.mutedChanged=new s(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new m,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=l(),this.scratchCameraShakeSample=l(),this.outlined=[],this.baseCamera=e.camera,this.sourceCamera=e.camera,e.onLoop(e=>{this.handleFrame(e)}),e.camera.add(this.audioListener),window.hology_view=this}get activeBackend(){return this.view.activeBackend}get requestedBackend(){return this.view.requestedBackend}get vfxBackendPreference(){return this.view.vfxBackendPreference}get webgpuVfxInstancesPerTemplate(){return this.view.webgpuVfxInstancesPerTemplate}get webgpuVfxTemplateMemoryBudgetBytes(){return this.view.webgpuVfxTemplateMemoryBudgetBytes}get webgpuVfxWorldMemoryBudgetBytes(){return this.view.webgpuVfxWorldMemoryBudgetBytes}get webgpuVfxColdTemplateSeconds(){return this.view.webgpuVfxColdTemplateSeconds}get webGpuDevice(){return this.view.webGpuDevice}get experimentalWebGpuDevice(){return this.webGpuDevice}registerWebGpuRenderGraphExtension(e){return this.view.registerWebGpuRenderGraphExtension(e)}registerExperimentalWebGpuRenderGraphExtension(e){return this.registerWebGpuRenderGraphExtension(e)}handleFrame(e){let t=this._timeScale,a=0;this._hitStopRemaining>0?(this._hitStopRemaining-=1e3*e,this._hitStopRemaining<=0&&(this._hitStopRemaining=0),t=0):a=e*this._timeScale,this.advanceGameplayCameraShakes(a),this.tick.next(a),this.scheduler.update(1e3*a),this.lateTick.next(a),this.view.simulationTimeScale=t,this.refreshCameraPresentation()}set timeScale(e){this._timeScale=Math.max(0,e)}get timeScale(){return this._timeScale}applyHitStop(e){this._hitStopRemaining=Math.max(this._hitStopRemaining,e)}set fpsCap(e){this.view.fpsCap=e}get fpsCap(){return this.view.fpsCap}set showStats(e){this.view.showStats=e}get showStats(){return this.view.showStats}setProfilingEnabled(e){this.view.setProfilingEnabled(e)}getLastFrameProfile(){return this.view.getLastFrameProfile()}setLightVolume(e){this.view.lightVolume=e}getLightVolume(){return this.view.lightVolume}addPostProcessVolume(e){this.view.addPostProcessVolume(e)}removePostProcessVolume(e){this.view.removePostProcessVolume(e)}addPostProcessEffect(e,t){return this.view.addPostProcessEffect(e,t)}onUpdate(e){return null==e?this.tick:this.tick.pipe(h(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(h(e.disposed))}setCamera(e){const t=e instanceof i?e:e.camera.instance;this.baseCamera=t,0===this.cameraOverrides.length&&(this.sourceCamera=t,this.refreshCameraPresentation())}getCamera(){return this.view.camera}getSourceCamera(){return this.sourceCamera}getBaseCamera(){return this.baseCamera}applyCameraShake(e){const t=function(e){return{duration:Math.max(0,e.duration??0),attack:e.attack??0,decay:e.decay??0,frequency:e.frequency??24,positionAmplitude:e.positionAmplitude?[...e.positionAmplitude]:[0,0,0],rotationAmplitude:e.rotationAmplitude?[...e.rotationAmplitude]:[0,0,0],seed:e.seed}}(e);if(t.duration<=0)return{release:()=>{}};const a={id:++this.cameraShakeId,request:t,elapsedTime:0,seedOverride:t.seed};this.gameplayCameraShakes.push(a),this.refreshCameraPresentation();let i=!1;return{release:()=>{i||(i=!0,this.releaseGameplayCameraShake(a.id))}}}setCameraShakeContribution(e,t,a,i,r){if(a.duration<=0)return void this.removeCameraShakeContribution(e,t);let s=this.cameraShakeContributions.get(e);s||(s=new Map,this.cameraShakeContributions.set(e,s));const n=s.get(t);n?(n.request=a,n.elapsedTime=Math.max(0,i),n.seedOverride=r):s.set(t,{key:t,request:a,elapsedTime:Math.max(0,i),seedOverride:r}),this.refreshCameraPresentation()}removeCameraShakeContribution(e,t){const a=this.cameraShakeContributions.get(e);a?.delete(t)&&(0===a.size&&this.cameraShakeContributions.delete(e),this.refreshCameraPresentation())}clearCameraShakeContributionsForOwner(e){this.cameraShakeContributions.delete(e)&&this.refreshCameraPresentation()}pushCameraOverride(e,t,a=0){const i={id:++this.cameraOverrideId,camera:e,owner:t,priority:a};this.cameraOverrides.push(i),this.applyTopCameraOverride();let r=!1;return{release:()=>{r||(r=!0,this.releaseCameraOverrideEntry(i))}}}releaseCameraOverridesForOwner(e){const t=this.cameraOverrides.filter(t=>t.owner!==e);t.length!==this.cameraOverrides.length&&(this.cameraOverrides=t,this.applyTopCameraOverride())}releaseCameraOverrideEntry(e){const t=this.cameraOverrides.indexOf(e);-1!==t&&(this.cameraOverrides.splice(t,1),this.applyTopCameraOverride())}applyTopCameraOverride(){const e=this.getTopCameraOverride();this.sourceCamera=e?.camera??this.baseCamera,this.refreshCameraPresentation()}getTopCameraOverride(){let e;for(const t of this.cameraOverrides)(!e||t.priority>e.priority||t.priority===e.priority&&t.id>e.id)&&(e=t);return e}applyRenderedCamera(e){this.view.camera!==e&&this.view.setCamera(e),e.add(this.audioListener)}releaseGameplayCameraShake(e){const t=this.gameplayCameraShakes.findIndex(t=>t.id===e);-1!==t&&(this.gameplayCameraShakes.splice(t,1),this.refreshCameraPresentation())}advanceGameplayCameraShakes(e){if(!(e<=0||0===this.gameplayCameraShakes.length))for(let t=this.gameplayCameraShakes.length-1;t>=0;t--){const a=this.gameplayCameraShakes[t];a.elapsedTime+=e,a.elapsedTime>a.request.duration&&this.gameplayCameraShakes.splice(t,1)}}refreshCameraPresentation(){if(!this.hasActiveCameraShake())return void this.applyRenderedCamera(this.sourceCamera);const e=this.ensurePresentationCamera();this.copyCameraState(this.sourceCamera,e),this.accumulateCameraShakeSamples(),this.applyCameraShakeSample(e),this.applyRenderedCamera(e)}hasActiveCameraShake(){if(this.gameplayCameraShakes.length>0)return!0;for(const e of this.cameraShakeContributions.values())if(e.size>0)return!0;return!1}ensurePresentationCamera(){return this.presentationCamera||(this.presentationCamera=new o.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(S)),t.quaternion.copy(e.getWorldQuaternion(w)),t.scale.copy(e.getWorldScale(f)),t.layers.mask=e.layers.mask,e instanceof o.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect,t.zoom=e.zoom,t.focus=e.focus,t.filmGauge=e.filmGauge,t.filmOffset=e.filmOffset,t.view=null==e.view?null:{enabled:e.view.enabled,fullWidth:e.view.fullWidth,fullHeight:e.view.fullHeight,offsetX:e.view.offsetX,offsetY:e.view.offsetY,width:e.view.width,height:e.view.height},t.updateProjectionMatrix()):(t.projectionMatrix.copy(e.projectionMatrix),t.projectionMatrixInverse.copy(e.projectionMatrixInverse))}accumulateCameraShakeSamples(){u(this.accumulatedCameraShakeSample);for(let e=0;e<this.gameplayCameraShakes.length;e++)this.accumulateCameraShakeEntry(this.gameplayCameraShakes[e]);for(const e of this.cameraShakeContributions.values())for(const t of e.values())this.accumulateCameraShakeEntry(t)}accumulateCameraShakeEntry(e){const t=c(e.request,e.elapsedTime,this.scratchCameraShakeSample,e.seedOverride);if(t)for(let e=0;e<3;e++)this.accumulatedCameraShakeSample.position[e]+=t.position[e],this.accumulatedCameraShakeSample.rotation[e]+=t.rotation[e]}applyCameraShakeSample(e){k.copy(e.quaternion),y.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),y.applyQuaternion(k),e.position.add(y),x.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),P.setFromEuler(x),e.quaternion.copy(k).multiply(P),e.updateMatrixWorld(!0)}setMuted(e){this._muted=e,this.applyAudioGain(),this.mutedChanged.next(e)}getMuted(){return this._muted}set masterVolume(e){this._masterVolume=Math.min(Math.max(e,0),1),this.applyAudioGain()}get masterVolume(){return this._masterVolume}set cameraShakeIntensity(e){this._cameraShakeIntensity=Math.min(Math.max(e,0),1),this.refreshCameraPresentation()}get cameraShakeIntensity(){return this._cameraShakeIntensity}applyAudioGain(){this.audioListener.gain.gain.setValueAtTime(this._muted?0:this._masterVolume,this.audioListener.context.currentTime)}setOutlined(e){this.outlined.length=0;const t=this.outlined;for(let a=0;a<e.length;a++)t[a]=e[a];this.view.setSelectedObjects(t),this.view.setEnableOutlines(e.length>0)}getOutlined(){return this.outlined}addOutlined(e){this.outlined.includes(e)||(this.outlined.push(e),this.view.setSelectedObjects(this.outlined),this.view.setEnableOutlines(!0))}removeOutlined(e){const t=this.outlined.indexOf(e);-1!==t&&(this.outlined.splice(t,1),this.view.setSelectedObjects(this.outlined))}setOutlineColor(e){this.view.outlinePass?.visibleEdgeColor.copy(e)}getOutlineColor(){return this.view.outlinePass?.visibleEdgeColor}setOutlineThickness(e){this.view.outlinePass.edgeThickness=e}getOutlineThickness(){return this.view.outlinePass.edgeThickness}get htmlElement(){return this.view.container}getViewportSize(e=g){return this.view.getClientSize(e)}get paused(){return this.view.paused}set paused(e){e!=this.paused&&(e?this.pauseRendering():this.unpauseRendering())}pauseRendering(){this.view.paused=!0,this.pausedChanged.next(this.view.paused),this.scheduler.pause()}unpauseRendering(){this.view.paused=!1,this.pausedChanged.next(this.view.paused),this.scheduler.resume()}setInterval(e,t,a){return this.scheduler.setInterval(e,t,a)}clearInterval(e){this.scheduler.clearInterval(e)}dispose(){this.view.running&&this.view.stop(),this.scheduler.dispose(),this.cameraOverrides.length=0,this.gameplayCameraShakes.length=0,this.cameraShakeContributions.clear(),this.audioListener.removeFromParent(),this.tick.complete(),this.lateTick.complete(),this.paused=!0}createTimer(e){return this.scheduler.createTimer(e)}getScreenPosition(e,t=C,a=this.getViewportSize()){const i=this.getCamera();return p.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof o.PerspectiveCamera&&(v.setFromProjectionMatrix(p),!v.containsPoint(e))?null:(t.copy(e),t.project(i),t.x=(t.x+1)/2*a.x,t.y=(1-t.y)/2*a.y,t)}};d=e([a(),t("design:paramtypes",[r])],d);export{d as ViewController};const p=new o.Matrix4,C=new o.Vector3,g=new o.Vector2,v=new o.Frustum,S=new o.Vector3,f=new o.Vector3,w=new o.Quaternion,k=new o.Quaternion,y=new o.Vector3,x=new o.Euler(0,0,0,"XYZ"),P=new o.Quaternion;/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */