@hology/core 0.0.263 → 0.0.264

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 (31) hide show
  1. package/dist/effects/sequence/sequence-player.d.ts +1 -0
  2. package/dist/effects/sequence/sequence-player.js +1 -1
  3. package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
  4. package/dist/effects/vfx/vfx-actor.js +1 -1
  5. package/dist/gameplay/services/render.d.ts +3 -0
  6. package/dist/gameplay/services/render.js +1 -1
  7. package/dist/rendering/node-material-webgpu-resolver.d.ts +1 -0
  8. package/dist/rendering/node-material-webgpu-resolver.js +1 -1
  9. package/dist/rendering/webgpu-experimental-backend.d.ts +1 -0
  10. package/dist/rendering/webgpu-experimental-backend.js +1 -1
  11. package/dist/secondary-motion/budget.d.ts +26 -0
  12. package/dist/secondary-motion/budget.js +4 -0
  13. package/dist/secondary-motion/cache.d.ts +16 -0
  14. package/dist/secondary-motion/cache.js +4 -0
  15. package/dist/secondary-motion/runtime.d.ts +15 -0
  16. package/dist/secondary-motion/runtime.js +1 -1
  17. package/dist/secondary-motion/skinned-targets.d.ts +35 -0
  18. package/dist/secondary-motion/skinned-targets.js +4 -0
  19. package/dist/test/gpu-sprite-compiler.test.js +1 -1
  20. package/dist/test/node-material-webgpu-resolver.test.js +1 -1
  21. package/dist/test/secondary-motion-budget.test.d.ts +2 -0
  22. package/dist/test/secondary-motion-budget.test.js +4 -0
  23. package/dist/test/secondary-motion-cache.test.d.ts +2 -0
  24. package/dist/test/secondary-motion-cache.test.js +4 -0
  25. package/dist/test/secondary-motion-gpu-check.d.ts +2 -0
  26. package/dist/test/secondary-motion-gpu-check.js +4 -0
  27. package/dist/test/sequence-scene-binding.test.js +1 -1
  28. package/dist/test/vfx-playback-transform.test.d.ts +2 -0
  29. package/dist/test/vfx-playback-transform.test.js +4 -0
  30. package/package.json +4 -1
  31. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
- import{__decorate as e,__metadata as t}from"tslib";import{describe as a,expect as s,it as c,vi as n}from"vitest";import{Object3D as r}from"three";import{createGroupTrack as o,createObjectTrack as i,createSequenceData as u,createSpawnClipInstance as l,createSpawnTrack as d,createTransformKeyframe as p,createTransformSubTrack as f,remapSequenceObjectTrackTargets as g,SequenceRole as m}from"../effects/sequence/sequence-data.js";import{Parameter as q}from"../shader/parameter.js";import{prepareClassParameters as b,prepareCustomParamsFromType as y}from"../scene/materializer.js";import{SerializedParamType as h}from"../scene/model.js";n.mock("../gameplay/actors/builtin/index.js",()=>({builtInActors:{},default:{}})),n.mock("../gameplay/actors/index.js",()=>({CharacterAnimationComponent:class{},CharacterMovementComponent:class{}})),n.mock("../effects/vfx/vfx-actor.js",()=>({VfxActor:class{}})),n.mock("../effects/vfx/vfx-param.js",()=>({VisualEffect:class{}})),n.mock("../rendering.js",()=>({RenderingView:class{},setRenderingPaused:n.fn()})),n.hoisted(()=>{if("undefined"==typeof AudioBuffer&&Object.defineProperty(globalThis,"AudioBuffer",{configurable:!0,value:class{}}),"undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=("string"!=typeof t||!t.startsWith("is"))&&n.fn()),e[t]),set:(e,t,a)=>(e[t]=a,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})});class j{constructor(){this.sequenceData=u()}}e([q({label:"Sequence Data"}),t("design:type",Object)],j.prototype,"sequenceData",void 0),a("sequence scene bindings",()=>{c("binds scene object tracks nested inside groups",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=u(),c=o(),n=i(),l=new r;n.targetId="scene-actor",c.childTracks.push(n),a.tracks.push(c),t.load(a),t.bindObject("scene-actor",l),s(t.getActiveTrackObjects(n.id)).toEqual([l])}),c("gives role bindings precedence over a malformed scene target id",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=u(),c=i(),n=new r,o=new r;c.targetId="scene-actor",c.role=m.Self,a.tracks.push(c),t.load(a),t.bindObject("scene-actor",n),t.bindRole(m.Self,o),s(t.getActiveTrackObjects(c.id)).toEqual([o])}),c("preserves the existing parent of a role-bound spawn proxy",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=new r,c=new r,n=new r;a.add(c),c.add(n);const o=u();o.duration=1;const i=d();i.role=m.Self,i.clips.push(l(0,1)),o.tracks.push(i),t.setWorld({scene:a}),t.load(o),t.bindRole(m.Self,n),t.seek(.1),t.seek(.2),s(n.parent).toBe(c)}),c("removes a scene binding when its target can no longer be resolved",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=u(),c=i();c.targetId="scene-actor",a.tracks.push(c),t.load(a),t.bindObject("scene-actor",new r),t.unbindObject("scene-actor"),s(t.getActiveTrackObjects(c.id)).toEqual([])}),c("preserves the original transform when refreshing the same binding while scrubbing",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=u(),c=i(),n=f(),o=p(1);o.position=[5,0,0],n.keyframes.push(o),c.targetId="scene-actor",c.subTracks.push(n),a.tracks.push(c);const l=new r;l.position.set(2,0,0),t.load(a),t.bindObject("scene-actor",l),t.seek(1),t.bindObject("scene-actor",l),t.stop(),s(l.position.toArray()).toEqual([2,0,0])}),c("remaps grouped internal targets while preserving external references",()=>{const e=u(),t=o(),a=i(),c=i();a.targetId="internal-actor",c.targetId="external-actor",t.childTracks.push(a,c),e.tracks.push(t),g(e,new Map([["internal-actor","internal-actor-copy"]])),s(a.targetId).toBe("internal-actor-copy"),s(c.targetId).toBe("external-actor")}),c("preserves legacy raw inline sequence data when preparing editor params",()=>{const e=u(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=y(j,{sequenceData:e});s(a.sequenceData.type).toBe(h.SequenceData),s(a.sequenceData.value.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})}),c("materializes legacy Sequence-tagged inline scene sequence data without loading a sequence asset",async()=>{const e=u(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=await b({sequenceData:{type:h.Sequence,value:e}},j,{},{});s(a.sequenceData).toBe(e),s(a.sequenceData.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})}),c("materializes current inline scene sequence data without loading a sequence asset",async()=>{const e=u(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=await b({sequenceData:{type:h.SequenceData,value:e}},j,{},{});s(a.sequenceData).toBe(e),s(a.sequenceData.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})}),c("materializes legacy raw inline scene sequence data after reload",async()=>{const e=u(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=await b({sequenceData:e},j,{},{});s(a.sequenceData).toBe(e),s(a.sequenceData.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})})});/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import{describe as a,expect as s,it as n,vi as c}from"vitest";import{Object3D as o}from"three";import{createGroupTrack as r,createObjectTrack as i,createSequenceData as l,createSpawnClipInstance as d,createSpawnTrack as p,createTransformKeyframe as u,createTransformSubTrack as f,createVfxTrack as y,remapSequenceObjectTrackTargets as w,SequenceRole as q}from"../effects/sequence/sequence-data.js";import{Parameter as g}from"../shader/parameter.js";import{prepareClassParameters as m,prepareCustomParamsFromType as h}from"../scene/materializer.js";import{SerializedParamType as b}from"../scene/model.js";c.mock("../gameplay/actors/builtin/index.js",()=>({builtInActors:{},default:{}})),c.mock("../gameplay/actors/index.js",()=>({CharacterAnimationComponent:class{},CharacterMovementComponent:class{}})),c.mock("../effects/vfx/vfx-actor.js",()=>({VfxActor:class{}})),c.mock("../effects/vfx/vfx-param.js",()=>({VisualEffect:class{}})),c.mock("../rendering.js",()=>({RenderingView:class{},setRenderingPaused:c.fn()})),c.hoisted(()=>{if("undefined"==typeof AudioBuffer&&Object.defineProperty(globalThis,"AudioBuffer",{configurable:!0,value:class{}}),"undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=("string"!=typeof t||!t.startsWith("is"))&&c.fn()),e[t]),set:(e,t,a)=>(e[t]=a,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})});class v{constructor(){this.sequenceData=l()}}e([g({label:"Sequence Data"}),t("design:type",Object)],v.prototype,"sequenceData",void 0),a("sequence scene bindings",()=>{n("waits for an active parent and stops emitting when that parent clip ends",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=new o,n=new o;n.position.set(12,0,8),a.add(n);const r=l(),i=p();i.role=q.Self,i.clips.push(d(.2,.4));const u=y();u.parent={trackId:i.id};const f={id:"effect",vfxAssetId:"vfx",startTime:0,duration:1};u.clips.push(f),r.tracks.push(i,u),t.setWorld({scene:a}),t.load(r),t.bindRole(q.Self,n);const w=new o;a.add(w);const g={object:w,play:c.fn(),restart:c.fn(),stop:c.fn(),getParticleCount:()=>0},m=t;m.vfxService={};const h=m.getVfxClipKey(u,f);m.vfxActors.set(h,g),t.play(),s(g.play).not.toHaveBeenCalled(),s(m.activeVfxClips.has(h)).toBe(!1),t.seek(.3),s(g.play).toHaveBeenCalledOnce(),s(w.parent).toBe(n),g.stop.mockClear(),t.seek(.7),s(g.stop).toHaveBeenCalledOnce(),s(m.activeVfxClips.has(h)).toBe(!1),s(w.parent).toBe(a),s(w.position.toArray()).toEqual([12,0,8]),t.seek(.8),s(w.position.toArray()).toEqual([12,0,8]),s(g.play).toHaveBeenCalledOnce()}),n("does not start an async VFX if its parent ended while it was loading",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=new o,n=new o;a.add(n);const r=l(),i=p();i.role=q.Self,i.clips.push(d(0,.5));const u=y();u.parent={trackId:i.id};const f={id:"effect",vfxAssetId:"vfx",startTime:0,duration:1};let w;u.clips.push(f),r.tracks.push(i,u),t.setWorld({scene:a}),t.load(r),t.bindRole(q.Self,n),t.play();const g=t;g.vfxService={createFromAssetId:()=>new Promise(e=>{w=e})};const m=g.getVfxClipKey(u,f);g.activeVfxClips.add(m);const h=g.ensureVfxActor(u,f,m);t.seek(.7);const b={object:new o,play:c.fn()};w(b),await h,s(b.play).not.toHaveBeenCalled(),s(g.activeVfxClips.has(m)).toBe(!1)}),n("preserves the VFX world position when its parent spawn clip ends",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=new o,n=new o;n.position.set(12,0,8),a.add(n);const c=new o;c.position.set(0,.37,0),n.add(c);const r=l(),i=p();i.role=q.Self;const d=y();d.parent={trackId:i.id},r.tracks.push(i,d),t.setWorld({scene:a}),t.load(r),t.bindRole(q.Self,n);const u=t,f=`${d.id}-effect-vfx`;u.vfxActors.set(f,{object:c}),u.activeVfxClips.add(f),u.updateTrackParenting(d,void 0),s(c.parent).toBe(a),s(c.position.toArray()).toEqual([12,.37,8])}),n("parents an asynchronously created VFX before playback starts",async()=>{const{SequencePlayer:e,SequencePlaybackState:t}=await import("../effects/sequence/sequence-player.js"),a=new e,n=new o,r=new o;r.position.set(12,0,8),n.add(r);const i=l(),u=p();u.role=q.Self,u.clips.push(d(0,1));const f=y();f.parent={trackId:u.id};const w={id:"effect",vfxAssetId:"vfx",startTime:0,duration:1};f.clips.push(w),i.tracks.push(u,f),a.setWorld({scene:n}),a.load(i),a.bindRole(q.Self,r),a.seek(.1);const g=new o;n.add(g);const m=c.fn(()=>{s(g.parent).toBe(r),g.updateWorldMatrix(!0,!1),s(g.matrixWorld.elements.slice(12,15)).toEqual([12,0,8])}),h=a,b=c.fn();h.vfxService={createFromAssetId:c.fn(async()=>({object:g,play:m,restart:b}))},h._state.next(t.Playing);const v=h.getVfxClipKey(f,w);h.activeVfxClips.add(v),await h.ensureVfxActor(f,w,v),s(m).toHaveBeenCalledOnce(),n.add(g),await h.ensureVfxActor(f,w,v),s(m).toHaveBeenCalledTimes(2),s(b).toHaveBeenCalledOnce()}),n("binds scene object tracks nested inside groups",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=l(),n=r(),c=i(),d=new o;c.targetId="scene-actor",n.childTracks.push(c),a.tracks.push(n),t.load(a),t.bindObject("scene-actor",d),s(t.getActiveTrackObjects(c.id)).toEqual([d])}),n("gives role bindings precedence over a malformed scene target id",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=l(),n=i(),c=new o,r=new o;n.targetId="scene-actor",n.role=q.Self,a.tracks.push(n),t.load(a),t.bindObject("scene-actor",c),t.bindRole(q.Self,r),s(t.getActiveTrackObjects(n.id)).toEqual([r])}),n("preserves the existing parent of a role-bound spawn proxy",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=new o,n=new o,c=new o;a.add(n),n.add(c);const r=l();r.duration=1;const i=p();i.role=q.Self,i.clips.push(d(0,1)),r.tracks.push(i),t.setWorld({scene:a}),t.load(r),t.bindRole(q.Self,c),t.seek(.1),t.seek(.2),s(c.parent).toBe(n)}),n("removes a scene binding when its target can no longer be resolved",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=l(),n=i();n.targetId="scene-actor",a.tracks.push(n),t.load(a),t.bindObject("scene-actor",new o),t.unbindObject("scene-actor"),s(t.getActiveTrackObjects(n.id)).toEqual([])}),n("preserves the original transform when refreshing the same binding while scrubbing",async()=>{const{SequencePlayer:e}=await import("../effects/sequence/sequence-player.js"),t=new e,a=l(),n=i(),c=f(),r=u(1);r.position=[5,0,0],c.keyframes.push(r),n.targetId="scene-actor",n.subTracks.push(c),a.tracks.push(n);const d=new o;d.position.set(2,0,0),t.load(a),t.bindObject("scene-actor",d),t.seek(1),t.bindObject("scene-actor",d),t.stop(),s(d.position.toArray()).toEqual([2,0,0])}),n("remaps grouped internal targets while preserving external references",()=>{const e=l(),t=r(),a=i(),n=i();a.targetId="internal-actor",n.targetId="external-actor",t.childTracks.push(a,n),e.tracks.push(t),w(e,new Map([["internal-actor","internal-actor-copy"]])),s(a.targetId).toBe("internal-actor-copy"),s(n.targetId).toBe("external-actor")}),n("preserves legacy raw inline sequence data when preparing editor params",()=>{const e=l(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=h(v,{sequenceData:e});s(a.sequenceData.type).toBe(b.SequenceData),s(a.sequenceData.value.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})}),n("materializes legacy Sequence-tagged inline scene sequence data without loading a sequence asset",async()=>{const e=l(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=await m({sequenceData:{type:b.Sequence,value:e}},v,{},{});s(a.sequenceData).toBe(e),s(a.sequenceData.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})}),n("materializes current inline scene sequence data without loading a sequence asset",async()=>{const e=l(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=await m({sequenceData:{type:b.SequenceData,value:e}},v,{},{});s(a.sequenceData).toBe(e),s(a.sequenceData.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})}),n("materializes legacy raw inline scene sequence data after reload",async()=>{const e=l(),t=i();t.targetId="scene-actor",e.tracks.push(t);const a=await m({sequenceData:e},v,{},{});s(a.sequenceData).toBe(e),s(a.sequenceData.tracks[0]).toMatchObject({type:"object",targetId:"scene-actor"})})});/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=vfx-playback-transform.test.d.ts.map
@@ -0,0 +1,4 @@
1
+ import{Object3D as e,Vector3 as t}from"three";import{describe as o,expect as a,it as n,vi as r}from"vitest";r.mock("../gameplay/actors/builtin/index.js",()=>({builtInActors:{},default:{}})),r.mock("../gameplay/actors/index.js",()=>({CharacterAnimationComponent:class{},CharacterMovementComponent:class{}})),r.mock("../rendering.js",()=>({RenderingView:class{},setRenderingPaused:r.fn()})),r.hoisted(()=>{const e=new Proxy({},{get:(e,t)=>e[t]??(e[t]=r.fn()),set:(e,t,o)=>(e[t]=o,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})}),o("VFX playback transform",()=>{n("refreshes a reused GPU effect before resuming emission",async()=>{const{VfxActor:o}=await import("../effects/vfx/vfx-actor.js"),n=Object.create(o.prototype),s=new e;s.position.set(12,0,8),n.object=new e,n.object.position.set(0,0,1.75),s.add(n.object),n._worldPos=new t;const i=new t;n.gpuPrepared={},n.gpuHandle={active:!0,setPosition:r.fn(e=>i.copy(e)),setTransform:r.fn(),play:r.fn(()=>a(i.toArray()).toEqual([12,0,9.75])),restart:r.fn(()=>a(i.toArray()).toEqual([20,0,9.75]))},n.play(),a(n.gpuHandle.setTransform).toHaveBeenCalledWith(n.object.matrixWorld),a(n.gpuHandle.play).toHaveBeenCalledOnce(),s.position.x=20,n.restart(),a(n.gpuHandle.restart).toHaveBeenCalledOnce()})});/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hology/core",
3
- "version": "0.0.263",
3
+ "version": "0.0.264",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -10,6 +10,7 @@
10
10
  "build": "tsc",
11
11
  "lint": "eslint --max-warnings=0 \"**/*.{ts,tsx,mts,cts}\"",
12
12
  "test": "vitest --environment jsdom",
13
+ "test:secondary-motion:gpu": "node scripts/test-secondary-motion-gpu.mjs",
13
14
  "bump": "node scripts/bump.js",
14
15
  "terse": "node scripts/terse.js copy"
15
16
  },
@@ -34,6 +35,8 @@
34
35
  "./secondary-motion/data": "./dist/secondary-motion/data.js",
35
36
  "./secondary-motion/generation": "./dist/secondary-motion/generation.js",
36
37
  "./secondary-motion/runtime": "./dist/secondary-motion/runtime.js",
38
+ "./secondary-motion/budget": "./dist/secondary-motion/budget.js",
39
+ "./secondary-motion/cache": "./dist/secondary-motion/cache.js",
37
40
  "./scene/assets-provider": "./dist/scene/assets-provider.js",
38
41
  "./scene/materials/utils/material-painting": "./dist/scene/materials/utils/material-painting.js",
39
42
  "./scene/landscape/utils": "./dist/scene/landscape/utils.js",