@hology/core 0.0.212 → 0.0.214
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/effects/sequence/index.d.ts +1 -0
- package/dist/effects/sequence/index.js +1 -1
- package/dist/effects/sequence/sequence-action.d.ts +5 -0
- package/dist/effects/sequence/sequence-actor.d.ts +7 -0
- package/dist/effects/sequence/sequence-actor.js +1 -1
- package/dist/effects/sequence/sequence-animation-retiming.js +1 -1
- package/dist/effects/sequence/sequence-data.d.ts +9 -0
- package/dist/effects/sequence/sequence-data.js +1 -1
- package/dist/effects/sequence/sequence-player.d.ts +12 -1
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/sequence/sequence-transform.d.ts +10 -0
- package/dist/effects/sequence/sequence-transform.js +4 -0
- package/dist/effects/sequence/sequence-value-lane.d.ts +2 -0
- package/dist/effects/sequence/sequence-value-lane.js +1 -1
- package/dist/effects/vfx/initializsers.d.ts +4 -0
- package/dist/effects/vfx/initializsers.js +1 -1
- package/dist/effects/vfx/vfx-actor.d.ts +5 -0
- package/dist/effects/vfx/vfx-actor.js +1 -1
- package/dist/effects/vfx/vfx-asset.d.ts +2 -1
- package/dist/effects/vfx/vfx-asset.js +1 -1
- package/dist/effects/vfx/vfx-materializer.js +1 -1
- package/dist/effects/vfx/vfx-renderers.d.ts +1 -0
- package/dist/effects/vfx/vfx-renderers.js +1 -1
- package/dist/gameplay/actors/actor.d.ts +9 -5
- package/dist/gameplay/actors/actor.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-animation.d.ts +3 -0
- package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement-like.d.ts +2 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +13 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.d.ts +4 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.js +1 -1
- package/dist/gameplay/actors/builtin/components/mesh-component.d.ts +1 -0
- package/dist/gameplay/actors/builtin/components/mesh-component.js +1 -1
- package/dist/gameplay/actors/builtin/components/tween-component.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.d.ts +2 -0
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/actors/builtin/trigger-volume.d.ts +3 -3
- package/dist/gameplay/actors/builtin/trigger-volume.js +1 -1
- package/dist/gameplay/actors/camera/camera-component.d.ts +1 -3
- package/dist/gameplay/actors/camera/camera-component.js +1 -1
- package/dist/gameplay/actors/component.d.ts +9 -0
- package/dist/gameplay/actors/component.js +1 -1
- package/dist/gameplay/actors/type-registry.d.ts +10 -0
- package/dist/gameplay/actors/type-registry.js +4 -0
- package/dist/gameplay/animation/retarget.d.ts +50 -0
- package/dist/gameplay/animation/retarget.js +4 -0
- package/dist/gameplay/animation/root-motion.js +1 -1
- package/dist/gameplay/event-graph/actor-transform-properties.d.ts +6 -0
- package/dist/gameplay/event-graph/actor-transform-properties.js +4 -0
- package/dist/gameplay/event-graph/asset-actor-types.d.ts +3 -0
- package/dist/gameplay/event-graph/asset-actor-types.js +4 -0
- package/dist/gameplay/event-graph/asset-references.d.ts +12 -0
- package/dist/gameplay/event-graph/asset-references.js +4 -0
- package/dist/gameplay/event-graph/compiler.d.ts +107 -0
- package/dist/gameplay/event-graph/compiler.js +4 -0
- package/dist/gameplay/event-graph/decorators.d.ts +74 -0
- package/dist/gameplay/event-graph/decorators.js +4 -0
- package/dist/gameplay/event-graph/document-compiler.d.ts +107 -0
- package/dist/gameplay/event-graph/document-compiler.js +4 -0
- package/dist/gameplay/event-graph/event-graph-demo.d.ts +2 -0
- package/dist/gameplay/event-graph/event-graph-demo.js +4 -0
- package/dist/gameplay/event-graph/graph.d.ts +106 -0
- package/dist/gameplay/event-graph/graph.js +4 -0
- package/dist/gameplay/event-graph/index.d.ts +13 -0
- package/dist/gameplay/event-graph/index.js +4 -0
- package/dist/gameplay/event-graph/model.d.ts +71 -0
- package/dist/gameplay/event-graph/model.js +4 -0
- package/dist/gameplay/event-graph/nodes/execution-nodes.d.ts +115 -0
- package/dist/gameplay/event-graph/nodes/execution-nodes.js +4 -0
- package/dist/gameplay/event-graph/nodes/gameplay-nodes.d.ts +208 -0
- package/dist/gameplay/event-graph/nodes/gameplay-nodes.js +4 -0
- package/dist/gameplay/event-graph/nodes/index.d.ts +4 -0
- package/dist/gameplay/event-graph/nodes/index.js +4 -0
- package/dist/gameplay/event-graph/nodes/value-nodes.d.ts +53 -0
- package/dist/gameplay/event-graph/nodes/value-nodes.js +4 -0
- package/dist/gameplay/event-graph/registry.d.ts +33 -0
- package/dist/gameplay/event-graph/registry.js +4 -0
- package/dist/gameplay/event-graph/runtime-assets.d.ts +21 -0
- package/dist/gameplay/event-graph/runtime-assets.js +4 -0
- package/dist/gameplay/event-graph/runtime.d.ts +160 -0
- package/dist/gameplay/event-graph/runtime.js +4 -0
- package/dist/gameplay/event-graph/type-inference.d.ts +41 -0
- package/dist/gameplay/event-graph/type-inference.js +4 -0
- package/dist/gameplay/event-graph/types.d.ts +77 -0
- package/dist/gameplay/event-graph/types.js +4 -0
- package/dist/gameplay/index.d.ts +15 -2
- package/dist/gameplay/index.js +1 -1
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/input/input.d.ts +22 -17
- package/dist/gameplay/input/input.js +1 -1
- package/dist/gameplay/net/service/net-decorator.d.ts +1 -1
- package/dist/gameplay/net/service/net-decorator.js +1 -1
- package/dist/gameplay/net/service/net-serializer.js +1 -1
- package/dist/gameplay/net/service/net-service.d.ts +6 -6
- package/dist/gameplay/net/service/net-service.js +1 -1
- package/dist/gameplay/net/service/rpc-decorator.js +1 -1
- package/dist/gameplay/services/asset-loader.d.ts +7 -0
- package/dist/gameplay/services/asset-loader.js +1 -1
- package/dist/gameplay/services/physics/physics-system.d.ts +14 -0
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/world.d.ts +12 -0
- package/dist/gameplay/services/world.js +1 -1
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +7 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/assets-provider.d.ts +1 -0
- package/dist/scene/assets-provider.js +1 -1
- package/dist/scene/custom-param-deserialize.js +1 -1
- package/dist/scene/custom-param-runtime-types.js +1 -1
- package/dist/scene/materializer.d.ts +32 -0
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/model.d.ts +114 -2
- package/dist/scene/model.js +1 -1
- package/dist/scene/objects/prefab.js +1 -1
- package/dist/scene/runtime-asset-service.d.ts +7 -1
- package/dist/scene/runtime-asset-service.js +1 -1
- package/dist/shader/graph/compiler.d.ts +3 -0
- package/dist/shader/graph/compiler.js +1 -1
- package/dist/shader/graph/model.d.ts +1 -1
- package/dist/shader/graph/registry.js +1 -1
- package/dist/test/animation-retarget.test.d.ts +2 -0
- package/dist/test/animation-retarget.test.js +4 -0
- package/dist/test/event-graph-generated-code.test.d.ts +2 -0
- package/dist/test/event-graph-generated-code.test.js +4 -0
- package/dist/test/event-graph-types.test.d.ts +2 -0
- package/dist/test/event-graph-types.test.js +4 -0
- package/dist/test/event-graph.test.d.ts +2 -0
- package/dist/test/event-graph.test.js +4 -0
- package/dist/test/input.test.d.ts +2 -0
- package/dist/test/input.test.js +4 -0
- package/dist/test/net-character-movement.test.js +1 -1
- package/dist/test/prefab-instance-params.test.js +1 -1
- package/dist/test/runtime-asset-service.test.js +1 -1
- package/dist/test/sequence-camera-control.test.js +1 -1
- package/dist/test/sequence-scene-binding.test.d.ts +2 -0
- package/dist/test/sequence-scene-binding.test.js +4 -0
- package/dist/test/sequence-transform.test.d.ts +2 -0
- package/dist/test/sequence-transform.test.js +4 -0
- package/dist/test/shader-graph.test.js +1 -1
- package/dist/test/vfx-world-space-emitter-rotation.test.d.ts +2 -0
- package/dist/test/vfx-world-space-emitter-rotation.test.js +4 -0
- package/dist/test/world-prefab-spawn.test.js +1 -1
- package/package.json +10 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const SHADER_GRAPH_NODE_DEFINITIONS={"input.parameter":{kind:"input.parameter",label:"Parameter",category:"Inputs",inputs:[],outputs:[{name:"value",type:"dynamic"}]},"input.slider":{kind:"input.slider",label:"Slider",category:"Inputs",inputs:[],outputs:[{name:"value",type:"float"}]},"constant.boolean":{kind:"constant.boolean",label:"Boolean",category:"Inputs",inputs:[],outputs:[{name:"value",type:"boolean"}]},"constant.float":{kind:"constant.float",label:"Float",category:"Inputs",inputs:[],outputs:[{name:"value",type:"float"}]},"constant.vec2":{kind:"constant.vec2",label:"Vec2",category:"Inputs",inputs:[],outputs:[{name:"value",type:"vec2"}]},"constant.vec3":{kind:"constant.vec3",label:"Vec3",category:"Inputs",inputs:[],outputs:[{name:"value",type:"vec3"}]},"constant.rgba":{kind:"constant.rgba",label:"Color",category:"Inputs",inputs:[],outputs:[{name:"value",type:"rgba"}]},"builtin.uv":{kind:"builtin.uv",label:"UV",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec2"},{name:"u",type:"float"},{name:"v",type:"float"}]},"builtin.screenUv":{kind:"builtin.screenUv",label:"Screen UV",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec2"}]},"builtin.color":{kind:"builtin.color",label:"Color Attribute",category:"Attributes",inputs:[],outputs:[{name:"value",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"builtin.position":{kind:"builtin.position",label:"Position Attribute",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.worldPosition":{kind:"builtin.worldPosition",label:"World Position",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.objectPosition":{kind:"builtin.objectPosition",label:"Object Position",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.normal":{kind:"builtin.normal",label:"Normal Attribute",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.particle":{kind:"builtin.particle",label:"Particle",category:"Attributes",inputs:[],outputs:[{name:"energy",type:"float"},{name:"color",type:"rgb"},{name:"opacity",type:"float"},{name:"time",type:"float"}]},"builtin.time":{kind:"builtin.time",label:"Time",category:"Inputs",inputs:[],outputs:[{name:"value",type:"float"}]},"builtin.viewDir":{kind:"builtin.viewDir",label:"View Direction",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.camera":{kind:"builtin.camera",label:"Camera",category:"Inputs",inputs:[],outputs:[{name:"position",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"},{name:"near",type:"float"},{name:"far",type:"float"}]},"builtin.viewMatrix":{kind:"builtin.viewMatrix",label:"View Matrix",category:"Inputs",inputs:[],outputs:[{name:"value",type:"mat4"}]},"builtin.projectionMatrix":{kind:"builtin.projectionMatrix",label:"Projection Matrix",category:"Inputs",inputs:[],outputs:[{name:"value",type:"mat4"}]},"builtin.modelViewMatrix":{kind:"builtin.modelViewMatrix",label:"Model View Matrix",category:"Inputs",inputs:[],outputs:[{name:"value",type:"mat4"}]},"math.add":{kind:"math.add",label:"Add",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.subtract":{kind:"math.subtract",label:"Subtract",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.multiply":{kind:"math.multiply",label:"Multiply",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.divide":{kind:"math.divide",label:"Divide",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.oneMinus":{kind:"math.oneMinus",label:"One Minus",category:"Math",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.abs":e("math.abs","Abs","Math"),"math.sign":e("math.sign","Sign","Math"),"math.floor":e("math.floor","Floor","Math"),"math.ceil":e("math.ceil","Ceil","Math"),"math.fract":e("math.fract","Fract","Math"),"math.sin":e("math.sin","Sine","Trigonometry"),"math.cos":e("math.cos","Cosine","Trigonometry"),"math.tan":e("math.tan","Tangent","Trigonometry"),"math.asin":e("math.asin","Arc Sine","Trigonometry"),"math.acos":e("math.acos","Arc Cosine","Trigonometry"),"math.atan":e("math.atan","Arc Tangent","Trigonometry"),"math.atan2":{kind:"math.atan2",label:"Arc Tangent 2",category:"Trigonometry",inputs:[{name:"y",type:"dynamic"},{name:"x",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.radians":e("math.radians","Radians","Trigonometry"),"math.degrees":e("math.degrees","Degrees","Trigonometry"),"math.sqrt":e("math.sqrt","Square Root","Math"),"math.inverseSqrt":e("math.inverseSqrt","Inverse Square Root","Math"),"math.exp":e("math.exp","Exp","Math"),"math.exp2":e("math.exp2","Exp2","Math"),"math.log":e("math.log","Log","Math"),"math.log2":e("math.log2","Log2","Math"),"math.saturate":e("math.saturate","Saturate","Math"),"math.length":{kind:"math.length",label:"Length",category:"Vectors",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"math.normalize":e("math.normalize","Normalize","Vectors"),"math.clamp":{kind:"math.clamp",label:"Clamp",category:"Math",inputs:[{name:"value",type:"dynamic"},{name:"min",type:"dynamic",defaultValue:0},{name:"max",type:"dynamic",defaultValue:1}],outputs:[{name:"value",type:"dynamic"}]},"math.min":t("math.min","Min"),"math.max":t("math.max","Max"),"math.pow":t("math.pow","Power"),"math.mod":t("math.mod","Modulo"),"math.step":t("math.step","Step"),"math.smoothstep":{kind:"math.smoothstep",label:"Smoothstep",category:"Math",inputs:[{name:"edge0",type:"dynamic",defaultValue:0},{name:"edge1",type:"dynamic",defaultValue:1},{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.mix":{kind:"math.mix",label:"Mix",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"},{name:"t",type:"dynamic",defaultValue:.5}],outputs:[{name:"value",type:"dynamic"}]},"math.remap":{kind:"math.remap",label:"Remap",category:"Math",inputs:[{name:"value",type:"float"},{name:"inMin",type:"float",defaultValue:-1},{name:"inMax",type:"float",defaultValue:1},{name:"outMin",type:"float",defaultValue:0},{name:"outMax",type:"float",defaultValue:1}],outputs:[{name:"value",type:"float"}]},"math.reflect":{kind:"math.reflect",label:"Reflect",category:"Math",inputs:[{name:"incident",type:"dynamic"},{name:"normal",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.refract":{kind:"math.refract",label:"Refract",category:"Math",inputs:[{name:"incident",type:"dynamic"},{name:"normal",type:"dynamic"},{name:"ior",type:"float",defaultValue:1.5}],outputs:[{name:"value",type:"dynamic"}]},"math.derivative":{kind:"math.derivative",label:"Derivative",category:"Math",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.select":{kind:"math.select",label:"Select",category:"Math",inputs:[{name:"condition",type:"boolean"},{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"layer.mixPainted":{kind:"layer.mixPainted",label:"Mix Painted Layers",category:"Layers",inputs:[{name:"base",type:"dynamic"},...Array.from({length:8},(e,t)=>({name:`layer${t+1}`,label:`Layer ${t+1}`,type:"dynamic",optional:!0})),{name:"softness",type:"float",optional:!0},{name:"noiseScale",label:"Noise Scale",type:"float",optional:!0},{name:"noiseAmount",label:"Noise Amount",type:"float",optional:!0}],outputs:[{name:"value",type:"dynamic"}]},"math.dot":{kind:"math.dot",label:"Dot Product",category:"Vectors",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"math.distance":{kind:"math.distance",label:"Distance",category:"Vectors",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"math.cross":{kind:"math.cross",label:"Cross Product",category:"Vectors",inputs:[{name:"a",type:"vec3"},{name:"b",type:"vec3"}],outputs:[{name:"value",type:"vec3"}]},"compare.greaterThan":a("compare.greaterThan","Greater Than"),"compare.greaterThanOrEqual":a("compare.greaterThanOrEqual","Greater Than Or Equal"),"compare.lessThan":a("compare.lessThan","Less Than"),"compare.lessThanOrEqual":a("compare.lessThanOrEqual","Less Than Or Equal"),"compare.equal":a("compare.equal","Equal"),"compare.notEqual":a("compare.notEqual","Not Equal"),"boolean.not":{kind:"boolean.not",label:"Not",category:"Boolean",inputs:[{name:"value",type:"boolean"}],outputs:[{name:"value",type:"boolean"}]},"boolean.and":n("boolean.and","And"),"boolean.or":n("boolean.or","Or"),"compose.vec2":{kind:"compose.vec2",label:"Compose Vec2",category:"Vectors",inputs:[{name:"x",type:"float"},{name:"y",type:"float"}],outputs:[{name:"value",type:"vec2"}]},"compose.vec3":{kind:"compose.vec3",label:"Compose Vec3",category:"Vectors",inputs:[{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}],outputs:[{name:"value",type:"vec3"}]},"compose.vec4":{kind:"compose.vec4",label:"Compose Vec4",category:"Vectors",inputs:[{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"},{name:"w",type:"float"}],outputs:[{name:"value",type:"vec4"}]},"compose.rgba":{kind:"compose.rgba",label:"Compose RGBA",category:"Color",inputs:[{name:"r",type:"float",defaultValue:1},{name:"g",type:"float",defaultValue:1},{name:"b",type:"float",defaultValue:1},{name:"a",type:"float",defaultValue:1}],outputs:[{name:"value",type:"rgba"}]},"decompose.component":{kind:"decompose.component",label:"Component",category:"Vectors",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"decompose.split":{kind:"decompose.split",label:"Split Components",category:"Vectors",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"},{name:"w",type:"float"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"},{name:"u",type:"float"},{name:"v",type:"float"}]},"color.gradient":{kind:"color.gradient",label:"Gradient",category:"Color",inputs:[{name:"t",type:"float",defaultValue:.5}],outputs:[{name:"value",type:"rgba"}]},"utility.curve":{kind:"utility.curve",label:"Curve",category:"Utilities",inputs:[{name:"t",type:"float",defaultValue:.5}],outputs:[{name:"value",type:"float"}]},"color.hueShift":{kind:"color.hueShift",label:"Hue Shift",category:"Color",inputs:[{name:"color",type:"dynamic"},{name:"shift",type:"float"}],outputs:[{name:"value",type:"dynamic"}]},"color.blend":{kind:"color.blend",label:"Blend Colors",category:"Color",inputs:[{name:"base",type:"dynamic"},{name:"blend",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"color.desaturate":{kind:"color.desaturate",label:"Desaturate",category:"Color",inputs:[{name:"color",type:"dynamic"},{name:"fraction",type:"float",defaultValue:1}],outputs:[{name:"value",type:"dynamic"}]},"color.unpackNormal":{kind:"color.unpackNormal",label:"Unpack Normal",category:"Textures",inputs:[{name:"color",type:"dynamic"},{name:"scale",type:"float",defaultValue:1},{name:"normal",type:"vec3",optional:!0,inlineLiteral:!1}],outputs:[{name:"value",type:"vec3"}]},"texture.sampler2d":{kind:"texture.sampler2d",label:"Sampler 2D",category:"Texture",inputs:[{name:"texture",type:"texture2d"}],outputs:[{name:"value",type:"sampler2d"}]},"texture.sample2d":{kind:"texture.sample2d",label:"Sample Texture 2D",category:"Textures",inputs:[{name:"sampler",type:"sampler2d"},{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"rgba",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"texture.triplanarMapping":{kind:"texture.triplanarMapping",label:"Triplanar Mapping",category:"Textures",inputs:[{name:"sampler",type:"sampler2d"},{name:"scale",type:"float",defaultValue:1},{name:"normal",type:"vec3",inlineLiteral:!1},{name:"position",type:"vec3",inlineLiteral:!1}],outputs:[{name:"rgba",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"scene.sampleColor":{kind:"scene.sampleColor",label:"Sample Scene Color",category:"Texture",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"rgba",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"scene.sampleDepth":{kind:"scene.sampleDepth",label:"Sample Scene Depth",category:"Texture",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"depth",type:"float"},{name:"linearEyeDepth",type:"float"}]},"scene.fragmentDepth":{kind:"scene.fragmentDepth",label:"Fragment Depth",category:"Texture",inputs:[],outputs:[{name:"linearEyeDepth",type:"float"}]},"transform.translate":{kind:"transform.translate",label:"Translate",category:"Transform",inputs:[{name:"offset",type:"vec3",defaultValue:[0,0,0]}],outputs:[{name:"value",type:"mat4"}]},"transform.scale":{kind:"transform.scale",label:"Scale",category:"Transform",inputs:[{name:"scale",type:"vec3",defaultValue:[1,1,1]}],outputs:[{name:"value",type:"mat4"}]},"transform.rotateAxis":{kind:"transform.rotateAxis",label:"Rotate Axis",category:"Transform",inputs:[{name:"axis",type:"vec3",defaultValue:[0,1,0]},{name:"angle",type:"float",defaultValue:0}],outputs:[{name:"value",type:"mat4"}]},"uv.rotate":{kind:"uv.rotate",label:"Rotate UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"angle",type:"float",defaultValue:0},{name:"center",type:"vec2",optional:!0,defaultValue:[.5,.5]}],outputs:[{name:"value",type:"vec2"}]},"uv.twirl":{kind:"uv.twirl",label:"Twirl UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"strength",type:"float",defaultValue:1},{name:"center",type:"vec2",optional:!0,defaultValue:[.5,.5]},{name:"offset",type:"vec2",optional:!0,defaultValue:[0,0]}],outputs:[{name:"value",type:"vec2"}]},"uv.radial":{kind:"uv.radial",label:"Radial UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"coords",type:"vec2"},{name:"radius",type:"float"},{name:"angle",type:"float"}]},"uv.bulge":{kind:"uv.bulge",label:"Bulge UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"center",type:"vec2",optional:!0,defaultValue:[.5,.5]},{name:"power",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"vec2"}]},"uv.flipbook":{kind:"uv.flipbook",label:"Flipbook UV",category:"UV",inputs:[{name:"uv",type:"vec2",optional:!0,inlineLiteral:!1},{name:"columns",type:"float",optional:!0,defaultValue:1},{name:"rows",type:"float",optional:!0,defaultValue:1},{name:"fps",type:"float",optional:!0,defaultValue:60},{name:"time",type:"float",optional:!0,inlineLiteral:!1}],outputs:[{name:"value",type:"vec2"}]},"uv.pom":{kind:"uv.pom",label:"Parallax Occlusion",category:"UV",inputs:[{name:"uv",type:"vec2",optional:!0,inlineLiteral:!1},{name:"heightMap",type:"sampler2d"},{name:"heightScale",type:"float",optional:!0,defaultValue:.05}],outputs:[{name:"value",type:"vec2"}]},"shape.rectangle":{kind:"shape.rectangle",label:"Rectangle",category:"Shapes",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"width",type:"float",defaultValue:.5},{name:"height",type:"float",defaultValue:.5}],outputs:[{name:"value",type:"float"}]},"shape.roundedRectangle":{kind:"shape.roundedRectangle",label:"Rounded Rectangle",category:"Shapes",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"width",type:"float",defaultValue:.5},{name:"height",type:"float",defaultValue:.5},{name:"radius",type:"float",defaultValue:.1}],outputs:[{name:"value",type:"float"}]},"noise.simplex":{kind:"noise.simplex",label:"Simplex Noise",category:"Noise",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"scale",type:"float",optional:!0,defaultValue:8}],outputs:[{name:"value",type:"float"}]},"noise.voronoi2d":{kind:"noise.voronoi2d",label:"Voronoi",category:"Noise",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"scale",type:"float",optional:!0,defaultValue:8}],outputs:[{name:"value",type:"float"}]},"effect.fresnel":{kind:"effect.fresnel",label:"Fresnel",category:"Effects",inputs:[{name:"power",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"float"}]},"effect.edgeDepth":{kind:"effect.edgeDepth",label:"Edge Depth",category:"Effects",inputs:[{name:"power",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"float"}]},"effect.depthFade":{kind:"effect.depthFade",label:"Depth Fade",category:"Effects",inputs:[{name:"distance",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"float"}]},"util.panner":{kind:"util.panner",label:"Panner",category:"Utilities",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"speed",type:"vec2",defaultValue:[0,0]},{name:"tile",type:"vec2",defaultValue:[1,1]},{name:"time",type:"float",optional:!0,inlineLiteral:!1}],outputs:[{name:"value",type:"vec2"}]}};export const SHADER_GRAPH_NODE_KINDS=Object.keys(SHADER_GRAPH_NODE_DEFINITIONS);function e(e,t,a){return{kind:e,label:t,category:a,inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]}}function t(e,t){return{kind:e,label:t,category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]}}function a(e,t){return{kind:e,label:t,category:"Comparison",inputs:[{name:"a",type:"float"},{name:"b",type:"float"}],outputs:[{name:"value",type:"boolean"}]}}function n(e,t){return{kind:e,label:t,category:"Boolean",inputs:[{name:"a",type:"boolean"},{name:"b",type:"boolean"}],outputs:[{name:"value",type:"boolean"}]}}export function inlineLiteralTypeForPort(e,t){if(!1!==t.inlineLiteral)return"float"===t.type||"vec2"===t.type||"vec3"===t.type||"vec4"===t.type?t.type:"dynamic"===t.type&&function(e){return e.startsWith("math.")&&"math.reflect"!==e&&"math.refract"!==e}(e)?"float":void 0}export function defaultInlineLiteralValueForPort(e,t){const a=inlineLiteralTypeForPort(e,t);if(null!=a){if(void 0!==t.defaultValue)return l(t.defaultValue);if("math.multiply"===e)return 1;switch(a){case"float":return 0;case"vec2":return[0,0];case"vec3":return[0,0,0];case"vec4":return[0,0,0,1]}}}function l(e){return Array.isArray(e)?e.map(e=>l(e)):null!=e&&"object"==typeof e?Object.fromEntries(Object.entries(e).map(([e,t])=>[e,l(t)])):e}/*
|
|
1
|
+
export const SHADER_GRAPH_NODE_DEFINITIONS={"input.parameter":{kind:"input.parameter",label:"Parameter",category:"Inputs",inputs:[],outputs:[{name:"value",type:"dynamic"}]},"input.slider":{kind:"input.slider",label:"Slider",category:"Inputs",inputs:[],outputs:[{name:"value",type:"float"}]},"constant.boolean":{kind:"constant.boolean",label:"Boolean",category:"Inputs",inputs:[],outputs:[{name:"value",type:"boolean"}]},"constant.float":{kind:"constant.float",label:"Float",category:"Inputs",inputs:[],outputs:[{name:"value",type:"float"}]},"constant.vec2":{kind:"constant.vec2",label:"Vec2",category:"Inputs",inputs:[],outputs:[{name:"value",type:"vec2"}]},"constant.vec3":{kind:"constant.vec3",label:"Vec3",category:"Inputs",inputs:[],outputs:[{name:"value",type:"vec3"}]},"constant.rgba":{kind:"constant.rgba",label:"Color",category:"Inputs",inputs:[],outputs:[{name:"value",type:"rgba"}]},"builtin.uv":{kind:"builtin.uv",label:"UV",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec2"},{name:"u",type:"float"},{name:"v",type:"float"}]},"builtin.screenUv":{kind:"builtin.screenUv",label:"Screen UV",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec2"}]},"builtin.color":{kind:"builtin.color",label:"Color Attribute",category:"Attributes",inputs:[],outputs:[{name:"value",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"builtin.position":{kind:"builtin.position",label:"Position Attribute",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.worldPosition":{kind:"builtin.worldPosition",label:"World Position",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.objectPosition":{kind:"builtin.objectPosition",label:"Object Position",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.normal":{kind:"builtin.normal",label:"Normal Attribute",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.particle":{kind:"builtin.particle",label:"Particle",category:"Attributes",inputs:[],outputs:[{name:"energy",type:"float"},{name:"color",type:"rgb"},{name:"opacity",type:"float"},{name:"time",type:"float"}]},"builtin.time":{kind:"builtin.time",label:"Time",category:"Inputs",inputs:[],outputs:[{name:"value",type:"float"}]},"builtin.viewDir":{kind:"builtin.viewDir",label:"View Direction",category:"Attributes",inputs:[],outputs:[{name:"value",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}]},"builtin.camera":{kind:"builtin.camera",label:"Camera",category:"Inputs",inputs:[],outputs:[{name:"position",type:"vec3"},{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"},{name:"near",type:"float"},{name:"far",type:"float"}]},"builtin.viewMatrix":{kind:"builtin.viewMatrix",label:"View Matrix",category:"Inputs",inputs:[],outputs:[{name:"value",type:"mat4"}]},"builtin.projectionMatrix":{kind:"builtin.projectionMatrix",label:"Projection Matrix",category:"Inputs",inputs:[],outputs:[{name:"value",type:"mat4"}]},"builtin.modelViewMatrix":{kind:"builtin.modelViewMatrix",label:"Model View Matrix",category:"Inputs",inputs:[],outputs:[{name:"value",type:"mat4"}]},"math.add":{kind:"math.add",label:"Add",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.subtract":{kind:"math.subtract",label:"Subtract",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.multiply":{kind:"math.multiply",label:"Multiply",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.divide":{kind:"math.divide",label:"Divide",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.oneMinus":{kind:"math.oneMinus",label:"One Minus",category:"Math",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.abs":e("math.abs","Abs","Math"),"math.sign":e("math.sign","Sign","Math"),"math.floor":e("math.floor","Floor","Math"),"math.ceil":e("math.ceil","Ceil","Math"),"math.fract":e("math.fract","Fract","Math"),"math.sin":e("math.sin","Sine","Trigonometry"),"math.cos":e("math.cos","Cosine","Trigonometry"),"math.tan":e("math.tan","Tangent","Trigonometry"),"math.asin":e("math.asin","Arc Sine","Trigonometry"),"math.acos":e("math.acos","Arc Cosine","Trigonometry"),"math.atan":e("math.atan","Arc Tangent","Trigonometry"),"math.atan2":{kind:"math.atan2",label:"Arc Tangent 2",category:"Trigonometry",inputs:[{name:"y",type:"dynamic"},{name:"x",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.radians":e("math.radians","Radians","Trigonometry"),"math.degrees":e("math.degrees","Degrees","Trigonometry"),"math.sqrt":e("math.sqrt","Square Root","Math"),"math.inverseSqrt":e("math.inverseSqrt","Inverse Square Root","Math"),"math.exp":e("math.exp","Exp","Math"),"math.exp2":e("math.exp2","Exp2","Math"),"math.log":e("math.log","Log","Math"),"math.log2":e("math.log2","Log2","Math"),"math.saturate":e("math.saturate","Saturate","Math"),"math.length":{kind:"math.length",label:"Length",category:"Vectors",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"math.normalize":e("math.normalize","Normalize","Vectors"),"math.clamp":{kind:"math.clamp",label:"Clamp",category:"Math",inputs:[{name:"value",type:"dynamic"},{name:"min",type:"dynamic",defaultValue:0},{name:"max",type:"dynamic",defaultValue:1}],outputs:[{name:"value",type:"dynamic"}]},"math.min":t("math.min","Min"),"math.max":t("math.max","Max"),"math.pow":t("math.pow","Power"),"math.mod":t("math.mod","Modulo"),"math.step":t("math.step","Step"),"math.smoothstep":{kind:"math.smoothstep",label:"Smoothstep",category:"Math",inputs:[{name:"edge0",type:"dynamic",defaultValue:0},{name:"edge1",type:"dynamic",defaultValue:1},{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.mix":{kind:"math.mix",label:"Mix",category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"},{name:"t",type:"dynamic",defaultValue:.5}],outputs:[{name:"value",type:"dynamic"}]},"math.remap":{kind:"math.remap",label:"Remap",category:"Math",inputs:[{name:"value",type:"float"},{name:"inMin",type:"float",defaultValue:-1},{name:"inMax",type:"float",defaultValue:1},{name:"outMin",type:"float",defaultValue:0},{name:"outMax",type:"float",defaultValue:1}],outputs:[{name:"value",type:"float"}]},"math.reflect":{kind:"math.reflect",label:"Reflect",category:"Math",inputs:[{name:"incident",type:"dynamic"},{name:"normal",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.refract":{kind:"math.refract",label:"Refract",category:"Math",inputs:[{name:"incident",type:"dynamic"},{name:"normal",type:"dynamic"},{name:"ior",type:"float",defaultValue:1.5}],outputs:[{name:"value",type:"dynamic"}]},"math.derivative":{kind:"math.derivative",label:"Derivative",category:"Math",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"math.select":{kind:"math.select",label:"Select",category:"Math",inputs:[{name:"condition",type:"boolean"},{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"layer.mixPainted":{kind:"layer.mixPainted",label:"Mix Painted Layers",category:"Layers",inputs:[{name:"base",type:"dynamic"},...Array.from({length:8},(e,t)=>({name:`layer${t+1}`,label:`Layer ${t+1}`,type:"dynamic",optional:!0})),{name:"softness",type:"float",optional:!0},{name:"noiseScale",label:"Noise Scale",type:"float",optional:!0},{name:"noiseAmount",label:"Noise Amount",type:"float",optional:!0}],outputs:[{name:"value",type:"dynamic"}]},"math.dot":{kind:"math.dot",label:"Dot Product",category:"Vectors",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"math.distance":{kind:"math.distance",label:"Distance",category:"Vectors",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"math.cross":{kind:"math.cross",label:"Cross Product",category:"Vectors",inputs:[{name:"a",type:"vec3"},{name:"b",type:"vec3"}],outputs:[{name:"value",type:"vec3"}]},"compare.greaterThan":a("compare.greaterThan","Greater Than"),"compare.greaterThanOrEqual":a("compare.greaterThanOrEqual","Greater Than Or Equal"),"compare.lessThan":a("compare.lessThan","Less Than"),"compare.lessThanOrEqual":a("compare.lessThanOrEqual","Less Than Or Equal"),"compare.equal":a("compare.equal","Equal"),"compare.notEqual":a("compare.notEqual","Not Equal"),"boolean.not":{kind:"boolean.not",label:"Not",category:"Boolean",inputs:[{name:"value",type:"boolean"}],outputs:[{name:"value",type:"boolean"}]},"boolean.and":n("boolean.and","And"),"boolean.or":n("boolean.or","Or"),"compose.vec2":{kind:"compose.vec2",label:"Compose Vec2",category:"Vectors",inputs:[{name:"x",type:"float"},{name:"y",type:"float"}],outputs:[{name:"value",type:"vec2"}]},"compose.vec3":{kind:"compose.vec3",label:"Compose Vec3",category:"Vectors",inputs:[{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"}],outputs:[{name:"value",type:"vec3"}]},"compose.vec4":{kind:"compose.vec4",label:"Compose Vec4",category:"Vectors",inputs:[{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"},{name:"w",type:"float"}],outputs:[{name:"value",type:"vec4"}]},"compose.rgba":{kind:"compose.rgba",label:"Compose RGBA",category:"Color",inputs:[{name:"r",type:"float",defaultValue:1},{name:"g",type:"float",defaultValue:1},{name:"b",type:"float",defaultValue:1},{name:"a",type:"float",defaultValue:1}],outputs:[{name:"value",type:"rgba"}]},"decompose.component":{kind:"decompose.component",label:"Component",category:"Vectors",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"float"}]},"decompose.split":{kind:"decompose.split",label:"Split Components",category:"Vectors",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"x",type:"float"},{name:"y",type:"float"},{name:"z",type:"float"},{name:"w",type:"float"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"},{name:"u",type:"float"},{name:"v",type:"float"}]},"color.gradient":{kind:"color.gradient",label:"Gradient",category:"Color",inputs:[{name:"t",type:"float",defaultValue:.5}],outputs:[{name:"value",type:"rgba"}]},"utility.curve":{kind:"utility.curve",label:"Curve",category:"Utilities",inputs:[{name:"t",type:"float",defaultValue:.5}],outputs:[{name:"value",type:"float"}]},"utility.namedRerouteDeclaration":{kind:"utility.namedRerouteDeclaration",label:"Named Reroute Declaration",category:"Utilities",inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"utility.namedRerouteUsage":{kind:"utility.namedRerouteUsage",label:"Named Reroute Usage",category:"Utilities",inputs:[],outputs:[{name:"value",type:"dynamic"}]},"color.hueShift":{kind:"color.hueShift",label:"Hue Shift",category:"Color",inputs:[{name:"color",type:"dynamic"},{name:"shift",type:"float"}],outputs:[{name:"value",type:"dynamic"}]},"color.blend":{kind:"color.blend",label:"Blend Colors",category:"Color",inputs:[{name:"base",type:"dynamic"},{name:"blend",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]},"color.desaturate":{kind:"color.desaturate",label:"Desaturate",category:"Color",inputs:[{name:"color",type:"dynamic"},{name:"fraction",type:"float",defaultValue:1}],outputs:[{name:"value",type:"dynamic"}]},"color.unpackNormal":{kind:"color.unpackNormal",label:"Unpack Normal",category:"Textures",inputs:[{name:"color",type:"dynamic"},{name:"scale",type:"float",defaultValue:1},{name:"normal",type:"vec3",optional:!0,inlineLiteral:!1}],outputs:[{name:"value",type:"vec3"}]},"texture.sampler2d":{kind:"texture.sampler2d",label:"Sampler 2D",category:"Texture",inputs:[{name:"texture",type:"texture2d"}],outputs:[{name:"value",type:"sampler2d"}]},"texture.sample2d":{kind:"texture.sample2d",label:"Sample Texture 2D",category:"Textures",inputs:[{name:"sampler",type:"sampler2d"},{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"rgba",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"texture.triplanarMapping":{kind:"texture.triplanarMapping",label:"Triplanar Mapping",category:"Textures",inputs:[{name:"sampler",type:"sampler2d"},{name:"scale",type:"float",defaultValue:1},{name:"normal",type:"vec3",inlineLiteral:!1},{name:"position",type:"vec3",inlineLiteral:!1}],outputs:[{name:"rgba",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"scene.sampleColor":{kind:"scene.sampleColor",label:"Sample Scene Color",category:"Texture",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"rgba",type:"rgba"},{name:"rgb",type:"rgb"},{name:"r",type:"float"},{name:"g",type:"float"},{name:"b",type:"float"},{name:"a",type:"float"}]},"scene.sampleDepth":{kind:"scene.sampleDepth",label:"Sample Scene Depth",category:"Texture",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"depth",type:"float"},{name:"linearEyeDepth",type:"float"}]},"scene.fragmentDepth":{kind:"scene.fragmentDepth",label:"Fragment Depth",category:"Texture",inputs:[],outputs:[{name:"linearEyeDepth",type:"float"}]},"transform.translate":{kind:"transform.translate",label:"Translate",category:"Transform",inputs:[{name:"offset",type:"vec3",defaultValue:[0,0,0]}],outputs:[{name:"value",type:"mat4"}]},"transform.scale":{kind:"transform.scale",label:"Scale",category:"Transform",inputs:[{name:"scale",type:"vec3",defaultValue:[1,1,1]}],outputs:[{name:"value",type:"mat4"}]},"transform.rotateAxis":{kind:"transform.rotateAxis",label:"Rotate Axis",category:"Transform",inputs:[{name:"axis",type:"vec3",defaultValue:[0,1,0]},{name:"angle",type:"float",defaultValue:0}],outputs:[{name:"value",type:"mat4"}]},"uv.rotate":{kind:"uv.rotate",label:"Rotate UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"angle",type:"float",defaultValue:0},{name:"center",type:"vec2",optional:!0,defaultValue:[.5,.5]}],outputs:[{name:"value",type:"vec2"}]},"uv.twirl":{kind:"uv.twirl",label:"Twirl UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"strength",type:"float",defaultValue:1},{name:"center",type:"vec2",optional:!0,defaultValue:[.5,.5]},{name:"offset",type:"vec2",optional:!0,defaultValue:[0,0]}],outputs:[{name:"value",type:"vec2"}]},"uv.radial":{kind:"uv.radial",label:"Radial UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1}],outputs:[{name:"coords",type:"vec2"},{name:"radius",type:"float"},{name:"angle",type:"float"}]},"uv.bulge":{kind:"uv.bulge",label:"Bulge UV",category:"UV",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"center",type:"vec2",optional:!0,defaultValue:[.5,.5]},{name:"power",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"vec2"}]},"uv.flipbook":{kind:"uv.flipbook",label:"Flipbook UV",category:"UV",inputs:[{name:"uv",type:"vec2",optional:!0,inlineLiteral:!1},{name:"columns",type:"float",optional:!0,defaultValue:1},{name:"rows",type:"float",optional:!0,defaultValue:1},{name:"fps",type:"float",optional:!0,defaultValue:60},{name:"time",type:"float",optional:!0,inlineLiteral:!1}],outputs:[{name:"value",type:"vec2"}]},"uv.pom":{kind:"uv.pom",label:"Parallax Occlusion",category:"UV",inputs:[{name:"uv",type:"vec2",optional:!0,inlineLiteral:!1},{name:"heightMap",type:"sampler2d"},{name:"heightScale",type:"float",optional:!0,defaultValue:.05}],outputs:[{name:"value",type:"vec2"}]},"shape.rectangle":{kind:"shape.rectangle",label:"Rectangle",category:"Shapes",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"width",type:"float",defaultValue:.5},{name:"height",type:"float",defaultValue:.5}],outputs:[{name:"value",type:"float"}]},"shape.roundedRectangle":{kind:"shape.roundedRectangle",label:"Rounded Rectangle",category:"Shapes",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"width",type:"float",defaultValue:.5},{name:"height",type:"float",defaultValue:.5},{name:"radius",type:"float",defaultValue:.1}],outputs:[{name:"value",type:"float"}]},"noise.simplex":{kind:"noise.simplex",label:"Simplex Noise",category:"Noise",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"scale",type:"float",optional:!0,defaultValue:8}],outputs:[{name:"value",type:"float"}]},"noise.voronoi2d":{kind:"noise.voronoi2d",label:"Voronoi",category:"Noise",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"scale",type:"float",optional:!0,defaultValue:8}],outputs:[{name:"value",type:"float"}]},"effect.fresnel":{kind:"effect.fresnel",label:"Fresnel",category:"Effects",inputs:[{name:"power",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"float"}]},"effect.edgeDepth":{kind:"effect.edgeDepth",label:"Edge Depth",category:"Effects",inputs:[{name:"power",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"float"}]},"effect.depthFade":{kind:"effect.depthFade",label:"Depth Fade",category:"Effects",inputs:[{name:"distance",type:"float",optional:!0,defaultValue:1}],outputs:[{name:"value",type:"float"}]},"util.panner":{kind:"util.panner",label:"Panner",category:"Utilities",inputs:[{name:"uv",type:"vec2",inlineLiteral:!1},{name:"speed",type:"vec2",defaultValue:[0,0]},{name:"tile",type:"vec2",defaultValue:[1,1]},{name:"time",type:"float",optional:!0,inlineLiteral:!1}],outputs:[{name:"value",type:"vec2"}]}};export const SHADER_GRAPH_NODE_KINDS=Object.keys(SHADER_GRAPH_NODE_DEFINITIONS);function e(e,t,a){return{kind:e,label:t,category:a,inputs:[{name:"value",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]}}function t(e,t){return{kind:e,label:t,category:"Math",inputs:[{name:"a",type:"dynamic"},{name:"b",type:"dynamic"}],outputs:[{name:"value",type:"dynamic"}]}}function a(e,t){return{kind:e,label:t,category:"Comparison",inputs:[{name:"a",type:"float"},{name:"b",type:"float"}],outputs:[{name:"value",type:"boolean"}]}}function n(e,t){return{kind:e,label:t,category:"Boolean",inputs:[{name:"a",type:"boolean"},{name:"b",type:"boolean"}],outputs:[{name:"value",type:"boolean"}]}}export function inlineLiteralTypeForPort(e,t){if(!1!==t.inlineLiteral)return"float"===t.type||"vec2"===t.type||"vec3"===t.type||"vec4"===t.type?t.type:"dynamic"===t.type&&function(e){return e.startsWith("math.")&&"math.reflect"!==e&&"math.refract"!==e}(e)?"float":void 0}export function defaultInlineLiteralValueForPort(e,t){const a=inlineLiteralTypeForPort(e,t);if(null!=a){if(void 0!==t.defaultValue)return l(t.defaultValue);if("math.multiply"===e)return 1;switch(a){case"float":return 0;case"vec2":return[0,0];case"vec3":return[0,0,0];case"vec4":return[0,0,0,1]}}}function l(e){return Array.isArray(e)?e.map(e=>l(e)):null!=e&&"object"==typeof e?Object.fromEntries(Object.entries(e).map(([e,t])=>[e,l(t)])):e}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{describe as e,expect as t,it as o}from"vitest";import{Bone as n,AnimationClip as r,BufferGeometry as s,Group as a,MeshBasicMaterial as i,Quaternion as g,QuaternionKeyframeTrack as c,Skeleton as d,SkinnedMesh as p,Vector3 as l,VectorKeyframeTrack as u}from"three";import{areAnimationRigsCompatible as m,bakeRetargetedAnimationClip as b,createAutoAlignedRetargetPose as f,createDefaultAnimationRetargeter as w,extractAnimationRigs as h,findGeneratedAnimationOutput as B,getAnimationRigChainBoneNames as y,isAnimationClipCompatibleWithRig as L,resolveAnimationRigBasisRotation as k,resolveAnimationClipAssetForTarget as A,validateAnimationRetargeter as R,validateAnimationRig as v}from"../gameplay/animation/retarget.js";function T(e,t=!1){const o=["Root","Hips","Spine","Chest","Neck","Head","LeftUpperArm",...t?["LeftArmTwist"]:[],"LeftHand","RightUpperArm","RightHand","LeftUpLeg","LeftLeg","LeftFoot","RightUpLeg","RightLeg","RightFoot"],n=new Map(o.map(e=>[e,x(e)]));n.get("Root").add(n.get("Hips")),n.get("Hips").add(n.get("Spine"),n.get("LeftUpLeg"),n.get("RightUpLeg")),n.get("Spine").add(n.get("Chest")),n.get("Chest").add(n.get("Neck"),n.get("LeftUpperArm"),n.get("RightUpperArm")),n.get("Neck").add(n.get("Head")),t?(n.get("LeftUpperArm").add(n.get("LeftArmTwist")),n.get("LeftArmTwist").add(n.get("LeftHand"))):n.get("LeftUpperArm").add(n.get("LeftHand")),n.get("RightUpperArm").add(n.get("RightHand")),n.get("LeftUpLeg").add(n.get("LeftLeg")),n.get("LeftLeg").add(n.get("LeftFoot")),n.get("RightUpLeg").add(n.get("RightLeg")),n.get("RightLeg").add(n.get("RightFoot"));const r=new p(new s,new i);return r.name=e,r.add(n.get("Root")),r.bind(new d([...n.values()])),r}function x(e){const t=new n;return t.name=e,t.position.y="Root"===e?0:1,t}function P(e,t=new g){const o=F(T(`${e}Skeleton`),"Root");o.removeFromParent();const n=new a;n.name=e,n.quaternion.copy(t),n.add(o);const r=new a;return r.add(n),r.updateMatrixWorld(!0),r}function U(e){const t=[...T("Canonical").skeleton.bones],o=new Map(t.map((e,t)=>[e,t])),r=t.map(e=>e.parent instanceof n?o.get(e.parent)??-1:-1);for(const e of t)e.removeFromParent();const a=t.map(e=>{const t=new n;return t.name=e.name,t}),g=new p(new s,new i);g.name=e;for(let e=0;e<t.length;e++){const o=r[e];o<0?g.add(t[e]):a[o].add(t[e]),t[e].add(a[e])}return g.updateMatrixWorld(!0),g.bind(new d(a)),g}function M(e,t){let o=F(e,"LeftHand");for(const n of t){const t=x(n);o.add(t),e.skeleton.bones.push(t),o=t}e.updateMatrixWorld(!0),e.skeleton.calculateInverses()}function F(e,t){const o=e.skeleton.getBoneByName(t);if(null==o)throw new Error(`Missing test bone ${t}`);return o}function S(e,t){return{...e,previewMeshId:t}}e("animation retargeting assets",()=>{o("extracts stable hierarchy and bind-pose fingerprints",()=>{const e=h(T("Body")).rigs[0],o=h(T("Body")).rigs[0];t(e.topologyFingerprint).toBe(o.topologyFingerprint),t(e.bindPoseFingerprint).toBe(o.bindPoseFingerprint),t(e.skinnedMeshName).toBe("Body"),t(e.chains.map(e=>e.role)).toEqual(t.arrayContaining(["spine","leftArm","rightArm","leftLeg","rightLeg"]));const n=T("Body");F(n,"LeftHand").position.x+=.25;const r=h(n).rigs[0];t(r.topologyFingerprint).toBe(e.topologyFingerprint),t(r.bindPoseFingerprint).not.toBe(e.bindPoseFingerprint)}),o("extracts each distinct skeleton and reuses compatible rigs",()=>{const e=new a;e.add(T("BodyA"),T("BodyB")),t(h(e).rigs).toHaveLength(1);const o=T("BodyC");F(o,"LeftHand").position.x+=.1,e.add(o);const n=h(e).rigs;t(n).toHaveLength(2),t(m(S(n[0],"mesh-a"),S(n[0],"mesh-b"))).toBe(!0),t(m(S(n[0],"mesh-a"),S(n[1],"mesh-c"))).toBe(!1)}),o("extracts a rig from a standalone bone hierarchy",()=>{const e=new a,o=new n;o.name="Hips";const r=new n;r.name="Spine",r.position.y=1,o.add(r),e.add(o);const s=h(e);t(s.rigs).toHaveLength(1),t(s.skinnedMeshNames).toEqual(["Hips"]),t(s.rigs[0].skinnedMeshName).toBeUndefined(),t(s.rigs[0].bones.map(e=>e.name)).toEqual(["Hips","Spine"]),t(s.rigs[0].bones[1].parentIndex).toBe(0),t(s.rigs[0].bones[1].inverseBindMatrix).toHaveLength(16)}),o("canonicalizes same-named FBX bone wrappers and prefers a direct skinned hierarchy",()=>{const e=new a,o=U("WrappedLOD"),n=T("DirectLOD");e.add(o,n);const s=h(e),i=h(T("AnimationSource")).rigs[0];t(s.rigs).toHaveLength(1),t(s.skinnedMeshNames).toEqual(["DirectLOD"]),t(s.rigs[0].bones).toHaveLength(i.bones.length),t(s.rigs[0].topologyFingerprint).toBe(i.topologyFingerprint),t(s.rigs[0].bindPoseFingerprint).toBe(i.bindPoseFingerprint),t(v(S(s.rigs[0],"direct"))).toEqual([]);const g=S(s.rigs[0],"source"),d=S(i,"target");g.skinnedMeshName=void 0,g.basisPreset="yUp",d.basisPreset="yUp";const p=b({sourceRig:g,targetRig:d,retargeter:w("source-rig","target-rig",g,d),sourceObject:e,targetObject:T("AnimationTarget"),clip:new r("Wrapped source",1,[new c("Spine.quaternion",[0,1],[0,0,0,1,0,.3826834,0,.9238795])])}).tracks.find(e=>e.name.includes("[Spine]"));t(p).toBeDefined(),t(Array.from(p?.createInterpolant().evaluate(1)??[])).toEqual(t.arrayContaining([t.closeTo(0,5),t.closeTo(.3826834,5),t.closeTo(0,5),t.closeTo(.9238795,5)]));const l=U("StandaloneWrapped"),u=new a;for(;l.children.length>0;)u.add(l.children[0]);const m=h(u).rigs[0];t(m.bones).toHaveLength(i.bones.length),t(m.topologyFingerprint).toBe(i.topologyFingerprint),t(m.bindPoseFingerprint).toBe(i.bindPoseFingerprint)}),o("reports duplicate bone names and stale rig fingerprints",()=>{const e=h(T("Body")).rigs[0],o=S(e,"source-mesh"),n=S(e,"target-mesh"),r=w("source-rig","target-rig",o,n);n.bones[1].name=n.bones[0].name,n.bindPoseFingerprint="changed",t(v(n).map(e=>e.code)).toContain("duplicate-bone-names"),t(R(r,o,n).map(e=>e.code)).toContain("target-rig-changed")}),o("resolves semantic chain bones and generated output indexes",()=>{const e=S(h(T("Body")).rigs[0],"mesh");t(y(e,"leftLeg")).toEqual(["LeftUpLeg","LeftLeg","LeftFoot"]);const o=[{id:"retargeter",name:"A to B",type:"animationRetargeter",animationRetargeter:{...w("a","b",e,e),generatedOutputs:{walk:"walk-b"}}},{id:"walk-b",name:"Walk B",type:"animationclip",anim:{clip:"Walk",rigId:"b"}}];t(B(o,"walk","b")?.id).toBe("walk-b"),t(B(o,"walk","other")).toBeUndefined();const n={id:"walk",name:"Walk",type:"animationclip",anim:{clip:"Walk",rigId:"a"}};t(A(n,o,"b").id).toBe("walk-b"),t(()=>A(n,o,"missing")).toThrow(/Generate this source\/target output/);const s={...n,id:"legacy-walk",anim:{clip:"Walk"}};t(A(s,o,"b")).toBe(s),t(L(new r("Known",1,[new c(".bones[LeftHand].quaternion",[0],[0,0,0,1])]),e)).toBe(!0),t(L(new r("Other",1,[new c(".bones[Tail].quaternion",[0],[0,0,0,1])]),e)).toBe(!1)}),o("bakes target-named tracks at a minimum 60 Hz and maps root axes",()=>{const e=T("SourceBody"),o=T("TargetBody"),n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target");n.basisPreset="yUp",s.basisPreset="yUp";const a=w("source-rig","target-rig",n,s);a.bakeSettings.framesPerSecond=10,a.rootSettings.translationAxisMap=[3,2,-1];const i=new r("Move",1,[new u(".bones[Root].position",[0,1],[0,0,0,2,0,4]),new c(".bones[Spine].quaternion",[0,1],[0,0,0,1,0,0,0,1])]),g=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:i});t(g.name).toBe("Move"),t(g.tracks.some(e=>e.name.includes("Spine"))).toBe(!0),t(Math.max(...g.tracks.map(e=>e.times.length))).toBeGreaterThanOrEqual(2);const d=g.tracks.find(e=>e instanceof u);t(d).toBeInstanceOf(u),t(d?.name).toContain("Root"),t(d?.values.at(-3)).toBeCloseTo(4),t(d?.values.at(-1)).toBeCloseTo(-2)}),o("bakes from a standalone source skeleton without a skinned mesh",()=>{const e=P("AnimationSource"),o=T("TargetBody"),n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target");n.basisPreset="yUp",s.basisPreset="yUp";const a=w("source-rig","target-rig",n,s),i=(new g).setFromAxisAngle(new l(0,1,0),Math.PI/3),d=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:new r("Animation only",1,[new c(".bones[Spine].quaternion",[0,1],[0,0,0,1,...i.toArray()])])});t(d.tracks.some(e=>e.name.includes("[Spine]"))).toBe(!0)}),o("preserves the imported parent basis of a standalone source skeleton",()=>{const e=P("RotatedAnimationSource",(new g).setFromAxisAngle(new l(0,1,0),Math.PI/2)),o=T("TargetBody"),n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target");n.basisPreset="yUp",s.basisPreset="yUp";const a=w("source-rig","target-rig",n,s),i=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:new r("Move forward",1,[new u(".bones[Root].position",[0,1],[0,0,0,0,0,2])])}).tracks.find(e=>e instanceof u);t(i?.values.at(-3)).toBeCloseTo(2),t(i?.values.at(-2)).toBeCloseTo(0),t(i?.values.at(-1)).toBeCloseTo(0)}),o("detects a Z-up rig basis and converts root motion into target Y-up space",()=>{const e=T("ZUpSource");for(const t of e.skeleton.bones)t.position.set(t.position.x,0,t.position.y);e.updateMatrixWorld(!0),e.skeleton.calculateInverses();const o=T("YUpTarget"),n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target"),a=new l(0,0,1).applyQuaternion(k(n));t(a.angleTo(new l(0,1,0))).toBeLessThan(1e-6);const i=w("source-rig","target-rig",n,s),c=f(n,s,i).rotationOffsets[s.retargetRootBoneId];t((new g).fromArray(c).angleTo(new g)).toBeLessThan(1e-6);const d=b({sourceRig:n,targetRig:s,retargeter:i,sourceObject:e,targetObject:o,clip:new r("Vertical",1,[new u(".bones[Root].position",[0,1],[0,0,0,0,0,1])])}).tracks.find(e=>e instanceof u);t(d?.values.at(-2)).toBeCloseTo(1),t(d?.values.at(-1)).toBeCloseTo(0)}),o("combines source pelvis height with root motion when the target pelvis is its root",()=>{const e=T("SourceBody"),o=T("TargetBody"),n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target");n.basisPreset="yUp",s.basisPreset="yUp",s.retargetRootBoneId=s.pelvisBoneId;const a=w("source-rig","target-rig",n,s),i=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:new r("Crouch forward",1,[new u(".bones[Root].position",[0,1],[0,0,0,2,0,0]),new u(".bones[Hips].position",[0,1],[0,1,0,0,.6,0])])}).tracks.find(e=>e instanceof u&&e.name.includes("[Hips]"));t(i?.values.at(-3)).toBeCloseTo(2),t(i?.values.at(-2)).toBeCloseTo(.6),t(i?.values.at(-1)).toBeCloseTo(0)}),o("maps semantic chain position when target limb bone counts differ",()=>{const e=T("SourceBody"),o=T("TargetBody",!0),n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target");n.basisPreset="yUp",s.basisPreset="yUp";const a=w("source-rig","target-rig",n,s),i=new r("Wave",1,[new c(".bones[LeftUpperArm].quaternion",[0,1],[0,0,0,1,0,.3826834,0,.9238795])]),g=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:i});t(g.tracks.some(e=>e.name.includes("LeftArmTwist"))).toBe(!0),t(g.tracks.every(e=>!1===e.name.includes("Target"))).toBe(!0)}),o("transfers bind-relative rotation across different root coordinate bases",()=>{const e=T("SourceBody"),o=T("TargetBody");F(o,"Root").quaternion.setFromAxisAngle(new l(1,0,0),Math.PI/2),e.updateMatrixWorld(!0),o.updateMatrixWorld(!0),o.skeleton.calculateInverses();const n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target");n.basisPreset="yUp",s.basisPreset="yUp";const a=w("source-rig","target-rig",n,s),i=(new g).setFromAxisAngle(new l(0,1,0),Math.PI/3),d=new r("Turn",1,[new c(".bones[Spine].quaternion",[0,1],[0,0,0,1,...i.toArray()])]),p=F(e,"Spine"),u=F(o,"Spine"),m=p.getWorldQuaternion(new g),f=u.getWorldQuaternion(new g);p.quaternion.copy(i),e.updateMatrixWorld(!0);const B=p.getWorldQuaternion(new g).multiply(m.clone().invert()).multiply(f),y=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:d}).tracks.find(e=>e.name.includes("[Spine]"));t(y).toBeInstanceOf(c),u.quaternion.fromArray(y.values,y.values.length-4),o.updateMatrixWorld(!0),t(u.getWorldQuaternion(new g).angleTo(B)).toBeLessThan(1e-5)}),o("transfers root displacement through the target root parent basis",()=>{const e=T("SourceBody"),o=T("TargetBody");o.quaternion.setFromAxisAngle(new l(1,0,0),-Math.PI/2),F(o,"Root").quaternion.setFromAxisAngle(new l(1,0,0),Math.PI/2),e.updateMatrixWorld(!0),o.updateMatrixWorld(!0),o.skeleton.calculateInverses();const n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target");n.basisPreset="yUp",s.basisPreset="yUp";const a=w("source-rig","target-rig",n,s),i=new r("Move forward",1,[new u(".bones[Root].position",[0,1],[0,0,0,0,0,2])]),g=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:i}).tracks.find(e=>e instanceof u);t(g?.values.at(-3)).toBeCloseTo(0),t(g?.values.at(-2)).toBeCloseTo(-2),t(g?.values.at(-1)).toBeCloseTo(0)}),o("maps finger segments with different humanoid naming conventions",()=>{const e=T("SourceBody"),o=T("TargetBody");M(e,["mixamorigLeftHandIndex1","mixamorigLeftHandIndex2"]),M(o,["index1l","index2l"]);const n=S(h(e).rigs[0],"source"),s=S(h(o).rigs[0],"target"),a=w("source-rig","target-rig",n,s),i=(new g).setFromAxisAngle(new l(1,0,0),Math.PI/3),d=new r("Grip",1,[new c(".bones[mixamorigLeftHandIndex1].quaternion",[0,1],[0,0,0,1,...i.toArray()])]),p=b({sourceRig:n,targetRig:s,retargeter:a,sourceObject:e,targetObject:o,clip:d});t(p.tracks.some(e=>e.name.includes("[index1l]"))).toBe(!0),t(p.tracks.some(e=>e.name.includes("[index2l]"))).toBe(!0)}),o("creates a target pose that aligns mapped limb directions",()=>{const e=T("SourceBody"),o=T("TargetBody");F(o,"LeftUpperArm").quaternion.setFromAxisAngle(new l(0,0,1),Math.PI/4),o.updateMatrixWorld(!0),o.skeleton.calculateInverses();const n=S(h(e).rigs[0],"source"),r=S(h(o).rigs[0],"target"),s=w("source-rig","target-rig",n,r),a=f(n,r,s),i=F(o,"LeftUpperArm");i.quaternion.fromArray(r.bones.find(e=>"LeftUpperArm"===e.name).quaternion).multiply((new g).fromArray(a.rotationOffsets[r.bones.find(e=>"LeftUpperArm"===e.name).id])),o.updateMatrixWorld(!0);const c=F(o,"LeftHand").getWorldPosition(new l).sub(i.getWorldPosition(new l)).normalize(),d=F(e,"LeftHand").getWorldPosition(new l).sub(F(e,"LeftUpperArm").getWorldPosition(new l)).normalize();t(c.angleTo(d)).toBeLessThan(1e-5)}),o("auto-aligns using a root bone external parent from the bind pose",()=>{const e=T("SourceBody"),o=T("TargetBody");o.quaternion.setFromAxisAngle(new l(1,0,0),-Math.PI/2),F(o,"Root").quaternion.setFromAxisAngle(new l(1,0,0),Math.PI/2),o.updateMatrixWorld(!0),o.skeleton.calculateInverses();const n=S(h(e).rigs[0],"source"),r=S(h(o).rigs[0],"target");n.basisPreset="yUp",r.basisPreset="yUp";const s=w("source-rig","target-rig",n,r),a=f(n,r,s),i=r.bones.find(e=>"Spine"===e.name).id,c=(new g).fromArray(a.rotationOffsets[i]??[0,0,0,1]);t(c.angleTo(new g)).toBeLessThan(1e-5)})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{describe as e,expect as n,test as t}from"vitest";import{registerActorClass as o}from"../gameplay/actors/type-registry.js";import{EventGraphCompiler as a}from"../gameplay/event-graph/document-compiler.js";function i(e){return(new a).compile(e).beginPlay[0]}function r(e,n="value"){return{nodeId:e,port:n}}function s(e){return{value:e}}function d(e,n,t){return{from:{nodeId:e,port:n},to:{nodeId:t,port:"exec"}}}o("event-graph-generated.find-target",class{}),e("event graph generated code",()=>{t("resolves inline actor classes for pure world lookups",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"update",kind:"event.update"},{id:"find",kind:"actor.findByType",inputs:{actorClass:s("event-graph-generated.find-target")}},{id:"findAll",kind:"actor.findAllByType",inputs:{actorClass:s("event-graph-generated.find-target")}},{id:"log",kind:"debug.log",inputs:{value:r("find")}},{id:"logAll",kind:"debug.log",inputs:{value:r("findAll")}}],edges:[d("begin","then","log"),d("update","then","logAll")]},t=(new a).compile(e);n(t.beginPlay[0].async).toBe(!1),n(t.beginPlay[0].source).toContain('runtime.findActorByType(runtime.actorClass("event-graph-generated.find-target"))'),n(t.update[0].source).toContain('runtime.findActorsByType(runtime.actorClass("event-graph-generated.find-target"))')}),t("emits synchronous pure data flow inside a branch",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"branch",kind:"flow.branch",inputs:{condition:s(!0)}},{id:"one",kind:"constant.number",params:{value:1}},{id:"two",kind:"constant.number",params:{value:2}},{id:"sum",kind:"math.add",inputs:{a:r("one"),b:r("two")}},{id:"log",kind:"debug.log",inputs:{value:r("sum")}}],edges:[d("begin","then","branch"),d("branch","true","log")]});n(e.async).toBe(!1),n(e.source).toMatchInlineSnapshot('\n ""use strict"\n if (true) {\n const binary_1 = (1 + 2)\n console.log(binary_1)\n }"\n ')}),t("emits event values and persistent variable access without async code",()=>{const e={version:1,variables:[{name:"elapsed",defaultValue:0}],nodes:[{id:"update",kind:"event.update"},{id:"elapsed",kind:"variable.get",params:{variable:"elapsed"}},{id:"sum",kind:"math.add",inputs:{a:r("elapsed"),b:{nodeId:"update",port:"deltaTime"}}},{id:"set",kind:"variable.set",params:{variable:"elapsed"},inputs:{value:r("sum")}}],edges:[d("update","then","set")]},t=(new a).compile(e).update[0];n(t.async).toBe(!1),n(t.source).toMatchInlineSnapshot('\n ""use strict"\n const variable_1 = runtime.readValue(runtime.getVariable("elapsed"))\n const binary_2 = (variable_1 + eventValue)\n runtime.setVariable("elapsed", binary_2)"\n ')}),t("emits structured parallel branches and cancellable delay",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"parallel",kind:"flow.parallel",params:{ports:["slow","fast"]}},{id:"delay",kind:"flow.delay",inputs:{durationMs:s(100)}},{id:"slowLog",kind:"debug.log",inputs:{value:s("slow")}},{id:"fastLog",kind:"debug.log",inputs:{value:s("fast")}},{id:"doneLog",kind:"debug.log",inputs:{value:s("done")}}],edges:[d("begin","then","parallel"),d("parallel","slow","delay"),d("delay","then","slowLog"),d("parallel","fast","fastLog"),d("parallel","then","doneLog")]});n(e.async).toBe(!0),n(e.source).toMatchInlineSnapshot('\n ""use strict"\n await Promise.all([\n (async () => {\n await runtime.delay(100)\n console.log("slow")\n })(),\n (async () => {\n console.log("fast")\n })()\n ])\n console.log("done")"\n ')}),t("registers a game-time interval and continues immediately",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"interval",kind:"flow.interval",inputs:{intervalMs:s(250)}},{id:"tick",kind:"debug.log",inputs:{value:s("tick")}},{id:"started",kind:"debug.log",inputs:{value:s("started")}},{id:"clear",kind:"flow.clearInterval",inputs:{timerId:r("interval","timerId")}}],edges:[d("begin","then","interval"),d("interval","interval","tick"),d("interval","then","started"),d("started","then","clear")]});n(e.async).toBe(!1),n(e.source).toContain("runtime.setInterval("),n(e.source).toContain('"interval"'),n(e.source).toContain("250"),n(e.source).toContain('console.log("tick")'),n(e.source).toContain("runtime.clearInterval(out_timerId_"),n(e.source).toMatch(/runtime\.setInterval[\s\S]+console\.log\("started"\)[\s\S]+runtime\.clearInterval/)}),t("emits ordered sequence branches and an inclusive for loop",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"sequence",kind:"flow.sequence",params:{ports:["first","second"]}},{id:"first",kind:"debug.log",inputs:{value:s("first")}},{id:"second",kind:"debug.log",inputs:{value:s("second")}},{id:"loop",kind:"flow.forLoop",inputs:{firstIndex:s(2),lastIndex:s(4)}},{id:"index",kind:"debug.log",inputs:{value:r("loop","index")}},{id:"completed",kind:"debug.log",inputs:{value:s("completed")}}],edges:[d("begin","then","sequence"),d("sequence","first","first"),d("sequence","second","second"),d("sequence","then","loop"),d("loop","loopBody","index"),d("loop","completed","completed")]}).source;n(e.indexOf('console.log("first")')).toBeLessThan(e.indexOf('console.log("second")')),n(e).toContain("Number.isSafeInteger"),n(e).toContain("100000 iteration safety limit"),n(e).toMatch(/for \(let index_\d+ = firstIndex_\d+; index_\d+ <= lastIndex_\d+; index_\d+\+\+\)/),n(e).toMatch(/}\nconsole\.log\("completed"\)$/)}),t("emits a structured for-each loop with typed iteration values and latent bodies",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"forEach",kind:"flow.forEach",inputs:{array:{value:[10,20]}}},{id:"delay",kind:"flow.delay",inputs:{durationMs:s(1)}},{id:"element",kind:"debug.log",inputs:{value:r("forEach","arrayElement")}},{id:"index",kind:"debug.log",inputs:{value:r("forEach","arrayIndex")}},{id:"done",kind:"debug.log",inputs:{value:s("done")}}],edges:[d("begin","then","forEach"),d("forEach","loopBody","delay"),d("delay","then","element"),d("element","then","index"),d("forEach","completed","done")]});n(e.async).toBe(!0),n(e.source).toContain("const array_"),n(e.source).toContain("for (let index_"),n(e.source).toContain("await runtime.delay(1)"),n(e.source).toContain("console.log(out_arrayElement_"),n(e.source).toContain("console.log(out_arrayIndex_"),n(e.source).toMatch(/}\nconsole\.log\("done"\)$/)}),t("emits switch and try error routing",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"switch",kind:"flow.switch",params:{cases:[{value:"call",port:"call"}]},inputs:{value:s("call")}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"tryCall",kind:"actor.tryCallMethod",params:{method:"act",argumentCount:0},inputs:{target:r("actor")}},{id:"success",kind:"debug.log",inputs:{value:r("tryCall")}},{id:"error",kind:"debug.log",inputs:{value:{nodeId:"tryCall",port:"errorValue"}}},{id:"done",kind:"debug.log",inputs:{value:s("done")}}],edges:[d("begin","then","switch"),d("switch","call","tryCall"),d("tryCall","success","success"),d("tryCall","error","error"),d("tryCall","then","done")]});n(e.async).toBe(!1),n(e.source).toMatchInlineSnapshot('\n ""use strict"\n let out_value_1, out_errorValue_2\n switch ("call") {\n case "call": {\n const actor_4 = runtime.actor("hero")\n let succeeded_5 = false\n try {\n out_value_1 = runtime.callMethod(actor_4, "act", [])\n out_errorValue_2 = undefined\n succeeded_5 = true\n } catch (caught_3) {\n out_value_1 = undefined\n out_errorValue_2 = caught_3\n }\n if (succeeded_5) {\n console.log(out_value_1)\n } else {\n console.log(out_errorValue_2)\n }\n console.log("done")\n break\n }\n default: {\n \n }\n }"\n ')}),t("constructs fresh runtime vectors and compares their components",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"left",kind:"constant.vector3",params:{value:[1,2,3]}},{id:"right",kind:"constant.vector3",params:{value:[1,2,3]}},{id:"equal",kind:"compare.equal",inputs:{a:r("left"),b:r("right")}},{id:"branch",kind:"flow.branch",inputs:{condition:r("equal")}},{id:"log",kind:"debug.log",inputs:{value:r("left")}}],edges:[d("begin","then","branch"),d("branch","true","log")]});n(e.source).toContain("runtime.createVector3(1, 2, 3).equals(runtime.createVector3(1, 2, 3))"),n(e.source).toContain("console.log(runtime.createVector3(1, 2, 3))")}),t("emits runtime vector math while keeping scalar math native",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"vector",kind:"constant.vector3",params:{value:[1,2,3]}},{id:"offset",kind:"constant.vector3",params:{value:[4,5,6]}},{id:"two",kind:"constant.number",params:{value:2}},{id:"sum",kind:"math.add",inputs:{a:r("vector"),b:r("offset")}},{id:"scaled",kind:"math.multiply",inputs:{a:r("sum"),b:r("two")}},{id:"scalar",kind:"math.multiply",inputs:{a:r("two"),b:r("two")}},{id:"logVector",kind:"debug.log",inputs:{value:r("scaled")}},{id:"logScalar",kind:"debug.log",inputs:{value:r("scalar")}}],edges:[d("begin","then","logVector"),d("logVector","then","logScalar")]});n(e.source).toContain("runtime.mathAdd(runtime.createVector3(1, 2, 3), runtime.createVector3(4, 5, 6))"),n(e.source).toContain("runtime.mathMultiply(vectorMath_1, 2)"),n(e.source).toContain("const binary_3 = (2 * 2)")}),t("emits runtime vector utility operations",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"a",kind:"constant.vector3",params:{value:[1,0,0]}},{id:"b",kind:"constant.vector3",params:{value:[0,1,0]}},{id:"cross",kind:"vector.cross",inputs:{a:r("a"),b:r("b")}},{id:"normalize",kind:"vector.normalize",inputs:{value:r("cross")}},{id:"rotated",kind:"vector.applyRotation",inputs:{value:r("normalize"),rotation:{value:[0,.5,0]}}},{id:"distance",kind:"vector.distance",inputs:{a:r("a"),b:r("b")}},{id:"logVector",kind:"debug.log",inputs:{value:r("rotated")}},{id:"logDistance",kind:"debug.log",inputs:{value:r("distance")}}],edges:[d("begin","then","logVector"),d("logVector","then","logDistance")]});n(e.source).toContain("runtime.vectorCross(runtime.createVector3(1, 0, 0), runtime.createVector3(0, 1, 0))"),n(e.source).toContain("runtime.vectorNormalize(vector_1)"),n(e.source).toContain("runtime.vectorApplyRotation(vector_2, runtime.createEuler(0, 0.5, 0))"),n(e.source).toContain("runtime.vectorDistance(runtime.createVector3(1, 0, 0), runtime.createVector3(0, 1, 0))")}),t("keeps soft references scalar and emits async prefab placement with optional-handle routing",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"prefab",kind:"asset.reference",params:{reference:{assetId:"prefab-1",assetType:"prefab"}}},{id:"spawn",kind:"actor.spawnPrefab",inputs:{prefab:r("prefab"),position:{value:[1,2,3]},rotation:{value:[0,.5,0]}}},{id:"valid",kind:"flow.isValid",inputs:{value:r("spawn","mainActor")}},{id:"destroy",kind:"actor.destroy",inputs:{actor:r("valid")}}],edges:[d("begin","then","spawn"),d("spawn","then","valid"),d("valid","valid","destroy")]});n(e.async).toBe(!0),n(e.source).toContain('await runtime.spawnPrefab("prefab-1", runtime.createVector3(1, 2, 3), runtime.createEuler(0, 0.5, 0))'),n(e.source).toContain("!== null &&"),n(e.source).toContain("runtime.destroyActor("),n(e.source).not.toContain("assetType")}),t("continues after VFX start and registers a separate completion branch",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"vfx",kind:"vfx.play",inputs:{vfx:{value:{assetId:"vfx-1",assetType:"vfx"}}}},{id:"completed",kind:"debug.log",inputs:{value:{value:"completed"}}}],edges:[d("begin","then","vfx"),d("vfx","completed","completed")]},t=i(e);n(t.source).toContain("await runtime.playVfx("),n(t.source).toContain("runtime.onActorCompleted("),n(t.source).toContain('console.log("completed")');const o=structuredClone(e);o.nodes=o.nodes.filter(e=>"completed"!==e.id),o.edges=[d("begin","then","vfx")],n(i(o).source).not.toContain("runtime.onActorCompleted(")}),t("emits generic runtime callbacks for property and transform tweens",()=>{const e=i({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"rotate",kind:"transform.rotateBy",params:{curve:"InOutQuad",space:"world",axis:"z"},inputs:{target:r("actor"),angle:s(360),duration:s(2)}},{id:"completed",kind:"debug.log",inputs:{value:s("completed")}}],edges:[d("begin","then","rotate"),d("rotate","completed","completed")]});n(e.async).toBe(!1),n(e.source).toContain("runtime.tweenRotateBy("),n(e.source).toContain("360,"),n(e.source).toContain('"InOutQuad"'),n(e.source).toContain('"world"'),n(e.source).toContain('"z"'),n(e.source).toContain("async () => {"),n(e.source).toContain('console.log("completed")')})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import"reflect-metadata";import{Subject as a}from"rxjs";import{Euler as o,Vector2 as n,Vector3 as r}from"three";import{describe as i,expect as s,test as p,vi as d}from"vitest";d.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=d.fn()),e[t])});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e})}),d.mock("../gameplay/services/render.js",()=>({ViewController:class{}})),d.mock("../gameplay/services/physics/physics-system.js",()=>({PhysicsSystem:class{}}));import{Actor as c,BaseActor as u}from"../gameplay/actors/actor.js";import{ActorComponent as l,Component as v}from"../gameplay/actors/component.js";import{TriggerVolume as g,TriggerVolumeComponent as y}from"../gameplay/actors/builtin/trigger-volume.js";import{EVENT_GRAPH_ACTOR_CLASS_TYPE as m,EVENT_GRAPH_ACTOR_TYPE as b,EVENT_GRAPH_VOID_TYPE as k,EventGraphCallable as h,EventGraphCompiler as f,EventGraphEventSource as E,EventGraphProperty as q,analyzeEventGraphTypes as T,collectEventGraphAssetReferences as C,createEventGraphTypeContext as O,eventGraphTypeFromConstructor as I,eventGraphTypeName as j,eventGraphAssetType as w,eventGraphComponentType as x,eventGraphOptionalType as S,getEventGraphCallableInfo as P,getEventGraphEventSourceInfo as A,getEventGraphMembersForType as V,getEventGraphNodePorts as B,getEventGraphPropertyInfo as N,isEventGraphTypeAssignable as M,normalizeEventGraphDocument as D,validateEventGraphDocument as L}from"../gameplay/event-graph/index.js";let R=class extends l{constructor(){super(...arguments),this.score=10,this.damaged=new a,this.scored=new a,this.direction=new r(0,0,1)}applyDamage(e){return e>0}reset(){}project(e){return new n(e.x,e.y)}onScore(){return this.scored}onActorType(e){return new a}};e([q({type:Number}),t("design:type",Object)],R.prototype,"score",void 0),e([q({observableValueType:Number,writable:!1}),t("design:type",Object)],R.prototype,"damaged",void 0),e([q({type:r}),t("design:type",Object)],R.prototype,"direction",void 0),e([h({label:"Apply Damage",parameters:[{name:"amount",type:Number}],returns:Boolean}),t("design:type",Function),t("design:paramtypes",[Number]),t("design:returntype",Boolean)],R.prototype,"applyDamage",null),e([h({returns:k}),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],R.prototype,"reset",null),e([h({parameters:[{name:"position",type:r}],returns:n}),t("design:type",Function),t("design:paramtypes",[r]),t("design:returntype",n)],R.prototype,"project",null),e([E({label:"On Score",emits:Number}),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],R.prototype,"onScore",null),e([E({label:"On Actor Type",parameters:[{name:"actorType",type:m}],emits:b}),t("design:type",Function),t("design:paramtypes",[Object]),t("design:returntype",void 0)],R.prototype,"onActorType",null),R=e([v({typeId:"event-graph-test.stats"})],R);class z extends l{reset(){}}Reflect.defineMetadata("design:paramtypes",[],z.prototype,"reset"),Reflect.defineMetadata("design:returntype",void 0,z.prototype,"reset"),h()(z.prototype,"reset",Object.getOwnPropertyDescriptor(z.prototype,"reset"));let F=class extends u{constructor(){super(...arguments),this.stats=new R,this.intensity=0,this.enabled=!0,this.progress=0}};function H(e,t="value"){return{nodeId:e,port:t}}function W(e,t,a){return{from:{nodeId:e,port:t},to:{nodeId:a,port:"exec"}}}e([q({type:R,writable:!1}),t("design:type",Object)],F.prototype,"stats",void 0),e([q({type:Number}),t("design:type",Object)],F.prototype,"intensity",void 0),e([q({type:Boolean}),t("design:type",Object)],F.prototype,"enabled",void 0),e([q({type:Number,writable:!1}),t("design:type",Object)],F.prototype,"progress",void 0),F=e([c({typeId:"event-graph-test.hero"})],F),i("event graph types",()=>{p("narrows actor lookup results from static class inputs and keeps dynamic classes generic",()=>{const e={version:1,variables:[{name:"dynamicClass",type:m,defaultValue:"event-graph-test.hero"}],nodes:[{id:"find",kind:"actor.findByType",inputs:{actorClass:{value:"event-graph-test.hero"}}},{id:"findAll",kind:"actor.findAllByType",inputs:{actorClass:{value:"event-graph-test.hero"}}},{id:"forEach",kind:"flow.forEach",inputs:{array:H("findAll")}},{id:"classVariable",kind:"variable.get",params:{variable:"dynamicClass"}},{id:"findDynamic",kind:"actor.findByType",inputs:{actorClass:H("classVariable")}}],edges:[]},t=T(e);s(t.getInputType("find","actorClass")).toEqual({kind:"actorClass",classId:"event-graph-test.hero"}),s(t.getOutputType("find","value")).toEqual({kind:"optional",value:{kind:"actor",classId:"event-graph-test.hero"}}),s(t.getOutputType("findAll","value")).toEqual({kind:"array",element:{kind:"actor",classId:"event-graph-test.hero"}}),s(t.getInputType("forEach","array")).toEqual({kind:"array",element:{kind:"actor",classId:"event-graph-test.hero"}}),s(t.getOutputType("forEach","arrayElement")).toEqual({kind:"actor",classId:"event-graph-test.hero"}),s(t.getOutputType("forEach","arrayIndex")).toEqual({kind:"number"}),s(t.getOutputType("findDynamic","value")).toEqual({kind:"optional",value:b}),s(L(e).diagnostics).toEqual([]);const a=structuredClone(e);a.nodes[0].inputs.actorClass={value:"missing.actor"},s(L(a).diagnostics).toContainEqual(s.objectContaining({nodeId:"find",portId:"actorClass",message:'Actor class "missing.actor" does not exist'}))}),p("types tween endpoints from writable continuous actor properties",()=>{const e={version:1,nodes:[{id:"hero",kind:"actor.reference",params:{actorId:"hero"}},{id:"intensity",kind:"actor.tweenProperty",params:{property:"intensity",curve:"Linear"},inputs:{target:H("hero"),duration:{value:1},to:{value:1}}},{id:"enabled",kind:"actor.tweenProperty",params:{property:"enabled",curve:"Linear"},inputs:{target:H("hero"),duration:{value:1},to:{value:!0}}},{id:"progress",kind:"actor.tweenProperty",params:{property:"progress",curve:"Linear"},inputs:{target:H("hero"),duration:{value:1},to:{value:1}}}],edges:[]},t=O(new Map([["hero",F]]),"hero"),a=T(e,t);s(a.getInputType("intensity","to")).toEqual({kind:"number"}),s(a.diagnostics).toContainEqual(s.objectContaining({nodeId:"enabled",message:"Enabled cannot be tweened"})),s(a.diagnostics).toContainEqual(s.objectContaining({nodeId:"progress",message:"Progress is read-only"})),s(B(e.nodes[1],"inputs").map(e=>e.name)).toEqual(["exec","target","to","duration"]),s(B({id:"rotate",kind:"transform.rotateBy"},"inputs").map(e=>e.name)).toEqual(["exec","target","angle","duration"]);const o=structuredClone(e);o.nodes[1].inputs.from={value:0},s(L(o,t).diagnostics).toContainEqual(s.objectContaining({code:"invalid-structure",message:s.stringContaining("from")}))}),p("exposes reflected members and infers concrete actor/component pins",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"damaged",kind:"event.observable",params:{actorId:"hero",component:"stats",componentTypeId:"event-graph-test.stale-stats",property:"damaged"}},{id:"scoreSource",kind:"event.source",params:{actorId:"hero",component:"stats",componentTypeId:"event-graph-test.stale-stats",source:"onScore"}},{id:"hero",kind:"actor.reference",params:{actorId:"hero"}},{id:"actorPosition",kind:"actor.getProperty",params:{property:"position"},inputs:{target:H("hero")}},{id:"actorRotation",kind:"actor.getProperty",params:{property:"rotation"},inputs:{target:H("hero")}},{id:"actorScale",kind:"actor.getProperty",params:{property:"scale"},inputs:{target:H("hero")}},{id:"setActorScale",kind:"actor.setProperty",params:{property:"scale"},inputs:{target:H("hero"),value:{value:[1,1,1]}}},{id:"stats",kind:"actor.component",params:{property:"stats",componentTypeId:"event-graph-test.stats"},inputs:{target:H("hero")}},{id:"score",kind:"actor.getProperty",params:{property:"score"},inputs:{target:H("stats")}},{id:"apply",kind:"actor.callMethod",params:{method:"applyDamage",argumentCount:1},inputs:{target:H("stats"),arg0:H("score")}},{id:"reset",kind:"actor.callMethod",params:{method:"reset",argumentCount:0},inputs:{target:H("stats")}},{id:"bindScore",kind:"event.bindSource",params:{source:"onScore",argumentCount:0},inputs:{target:H("stats")}},{id:"bindActorType",kind:"event.bindSource",params:{source:"onActorType",argumentCount:0,arg0ActorClassId:"event-graph-test.hero"},inputs:{target:H("stats")}},{id:"bindScoreViaProperty",kind:"event.bindSource",params:{component:"stats",componentTypeId:"event-graph-test.stale-stats",source:"onScore",argumentCount:0},inputs:{target:H("hero")}}],edges:[W("begin","then","bindScoreViaProperty"),W("bindScoreViaProperty","then","apply")]},t=O(new Map([["hero",F]]),"hero"),a=T(e,t);s(a.diagnostics).toEqual([]),s(a.getOutputType("hero","value")).toEqual({kind:"actor",classId:"event-graph-test.hero"}),s(a.getOutputType("stats","value")).toEqual({kind:"component",classId:"event-graph-test.stats"}),s(a.getOutputType("score","value")).toEqual({kind:"number"}),s(a.getInputType("apply","arg0")).toEqual({kind:"number"}),s(a.getOutputType("apply","value")).toEqual({kind:"boolean"}),s(a.getOutputType("reset","value")).toEqual({kind:"void"}),s(a.getOutputType("damaged","value")).toEqual({kind:"number"}),s(a.getOutputType("scoreSource","value")).toEqual({kind:"number"}),s(a.getOutputType("bindScore","value")).toEqual({kind:"number"}),s(a.getOutputType("bindActorType","value")).toEqual({kind:"actor",classId:"event-graph-test.hero"}),s(a.getOutputType("bindScoreViaProperty","value")).toEqual({kind:"number"}),s(a.getOutputType("actorPosition","value")).toEqual({kind:"vector3"}),s(a.getOutputType("actorRotation","value")).toEqual({kind:"euler"}),s(a.getOutputType("actorScale","value")).toEqual({kind:"vector3"}),s(a.getInputType("setActorScale","value")).toEqual({kind:"vector3"}),s(t.resolveActorClass?.("$self")).toBe(F),s(P(R,"applyDamage")).toMatchObject({label:"Apply Damage",parameters:[{name:"amount",type:{kind:"number"}}],parametersKnown:!0,returnType:{kind:"boolean"}}),s(P(R,"reset")?.returnType).toEqual({kind:"void"}),s(P(z,"reset")?.returnType).toEqual({kind:"void"}),s(B(e.nodes.find(e=>"reset"===e.id),"outputs",a)).not.toEqual(s.arrayContaining([s.objectContaining({name:"value"})])),s(N(R,"score")?.type).toEqual({kind:"number"}),s(N(R,"damaged")).toMatchObject({type:{kind:"observable",value:{kind:"number"}},writable:!1}),s(N(R,"direction")?.type).toEqual({kind:"vector3"}),s(P(R,"project")).toMatchObject({parameters:[{name:"position",type:{kind:"vector3"}}],returnType:{kind:"vector2"}}),s(A(R,"onScore")).toMatchObject({label:"On Score",valueType:{kind:"number"},valueLabel:"Value"}),s(V(a.getOutputType("stats","value")).callables).toEqual(s.arrayContaining([s.objectContaining({methodName:"applyDamage"})])),s(V(a.getOutputType("stats","value")).eventSources).toEqual(s.arrayContaining([s.objectContaining({methodName:"onScore"})])),s(V(a.getOutputType("hero","value")).properties).toEqual(s.arrayContaining([s.objectContaining({propertyName:"position",type:{kind:"vector3"},writable:!0}),s.objectContaining({propertyName:"rotation",type:{kind:"euler"},writable:!0}),s.objectContaining({propertyName:"scale",type:{kind:"vector3"},writable:!0})])),s(V({kind:"actor"}).properties).toHaveLength(3),s(()=>(new f).compile(e,t)).not.toThrow();const o={...e,nodes:[...e.nodes,{id:"log-reset",kind:"debug.log"}],edges:[...e.edges,{from:{nodeId:"reset",port:"value"},to:{nodeId:"log-reset",port:"value"}}]};s(L(o,t).diagnostics).toEqual(s.arrayContaining([s.objectContaining({code:"unavailable-output-port",nodeId:"reset",portId:"value"})])),s(()=>(new f).compile(o,t)).toThrow("unavailable for its inferred type")}),p("exposes TriggerVolume overlap event sources through its graph-visible component",()=>{s(N(g,"trigger")).toMatchObject({propertyName:"trigger",writable:!1,type:{kind:"component",classId:"TriggerVolumeComponent"}});const e=V(x(y)).eventSources;s(e).toEqual(s.arrayContaining([s.objectContaining({methodName:"onBeginOverlap",valueLabel:"Other Actor",valueType:b}),s.objectContaining({methodName:"onEndOverlap",valueLabel:"Other Actor",valueType:b}),s.objectContaining({methodName:"onBeginOverlapWithActorType",parameters:[{name:"actorType",type:m}]}),s.objectContaining({methodName:"onEndOverlapWithActor",parameters:[{name:"actor",type:b}]})]))}),p("reports incompatible connections and prevents invalid code generation",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"text",kind:"constant.string",params:{value:"later"}},{id:"delay",kind:"flow.delay",inputs:{durationMs:H("text")}}],edges:[W("begin","then","delay")]};s(T(e).diagnostics).toEqual([s.objectContaining({severity:"error",nodeId:"delay",port:"durationMs",message:"Expected number, received string"})]),s(()=>(new f).compile(e)).toThrow("Expected number, received string")}),p("recognizes vector constructors and validates contextual tuple literals",()=>{s(I(n)).toEqual({kind:"vector2"}),s(I(r)).toEqual({kind:"vector3"}),s(j({kind:"vector3"})).toBe("vector3"),s(M({kind:"vector2"},{kind:"vector2"})).toBe(!0),s(M({kind:"vector2"},{kind:"vector3"})).toBe(!1);const e={version:1,variables:[{name:"position",type:{kind:"vector3"},defaultValue:[0,1,2]}],nodes:[{id:"vector2",kind:"constant.vector2",params:{value:[1,2]}},{id:"set",kind:"variable.set",params:{variable:"position"},inputs:{value:H("vector2")}}],edges:[]};s(T(e).diagnostics).toContainEqual(s.objectContaining({nodeId:"set",port:"value",message:"Expected vector3, received vector2"}));s(L({version:1,variables:[{name:"position",type:{kind:"vector3"},defaultValue:[0,1]}],nodes:[{id:"vector3",kind:"constant.vector3",params:{value:[1,2]}}],edges:[]}).diagnostics).toContainEqual(s.objectContaining({code:"invalid-structure",message:s.stringContaining("incompatible default value")}));s(L({version:1,nodes:[{id:"vector3",kind:"constant.vector3",params:{value:[1,2]}}],edges:[]}).diagnostics).toContainEqual(s.objectContaining({code:"invalid-structure",message:s.stringContaining("requires a finite vector3 tuple")}))}),p("contextualizes authored and untouched vector equality defaults",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"vector",kind:"constant.vector2",params:{value:[1,2]}},{id:"authored",kind:"compare.equal",inputs:{a:H("vector"),b:{value:[0,0]}}},{id:"untouched",kind:"compare.equal",inputs:{a:H("vector")}},{id:"branch",kind:"flow.branch",inputs:{condition:H("untouched")}}],edges:[W("begin","then","branch")]},t=T(e);s(t.diagnostics).toEqual([]),s(t.getInputType("authored","b")).toEqual({kind:"vector2"}),s(t.getInputType("untouched","b")).toEqual({kind:"vector2"}),s(L(e).diagnostics).toEqual([]),s((new f).compile(e).beginPlay[0].source).toContain("runtime.createVector2(1, 2).equals(runtime.createVector2(0, 0))")}),p("infers arithmetic nodes for numbers, vectors, and vector-scalar permutations",()=>{const e={version:1,nodes:[{id:"vector3",kind:"constant.vector3",params:{value:[1,2,3]}},{id:"vector2",kind:"constant.vector2",params:{value:[4,5]}},{id:"scale",kind:"constant.number",params:{value:2}},{id:"add",kind:"math.add",inputs:{a:H("vector3"),b:{value:[10,20,30]}}},{id:"leftScale",kind:"math.multiply",inputs:{a:H("scale"),b:H("vector2")}},{id:"rightScale",kind:"math.divide",inputs:{a:H("vector3"),b:H("scale")}},{id:"invalid",kind:"math.subtract",inputs:{a:H("vector2"),b:H("vector3")}}],edges:[]},t=T(e);s(t.getOutputType("add","value")).toEqual({kind:"vector3"}),s(t.getInputType("add","b")).toEqual({kind:"vector3"}),s(t.getOutputType("leftScale","value")).toEqual({kind:"vector2"}),s(t.getInputType("leftScale","a")).toEqual({kind:"number"}),s(t.getOutputType("rightScale","value")).toEqual({kind:"vector3"}),s(t.diagnostics).toContainEqual(s.objectContaining({nodeId:"invalid",message:"Subtract requires vector operands to have the same dimension, received vector2 and vector3"}))}),p("infers vector utility nodes across vector dimensions",()=>{const e={version:1,nodes:[{id:"vector3",kind:"constant.vector3",params:{value:[1,2,3]}},{id:"vector2",kind:"constant.vector2",params:{value:[4,5]}},{id:"length",kind:"vector.length",inputs:{value:H("vector3")}},{id:"normalize",kind:"vector.normalize",inputs:{value:H("vector2")}},{id:"distance",kind:"vector.distance",inputs:{a:H("vector2"),b:{value:[5,6]}}},{id:"lerp",kind:"vector.lerp",inputs:{a:H("vector3"),b:{value:[3,4,5]}}},{id:"cross",kind:"vector.cross",inputs:{a:H("vector3")}},{id:"applyRotation",kind:"vector.applyRotation",inputs:{value:H("vector3")}},{id:"invalidDot",kind:"vector.dot",inputs:{a:H("vector2"),b:H("vector3")}}],edges:[]},t=T(e);s(t.getOutputType("length","value")).toEqual({kind:"number"}),s(t.getOutputType("normalize","value")).toEqual({kind:"vector2"}),s(t.getInputType("distance","b")).toEqual({kind:"vector2"}),s(t.getOutputType("distance","value")).toEqual({kind:"number"}),s(t.getOutputType("lerp","value")).toEqual({kind:"vector3"}),s(t.getOutputType("cross","value")).toEqual({kind:"vector3"}),s(t.getOutputType("applyRotation","value")).toEqual({kind:"vector3"}),s(t.diagnostics).toContainEqual(s.objectContaining({nodeId:"invalidDot",message:"Dot Product requires matching vector dimensions, received vector2 and vector3"}))}),p("types soft asset references, optional handles, Euler literals, and catalog diagnostics",()=>{s(I(o)).toEqual({kind:"euler"}),s(j({kind:"euler"})).toBe("Rotation"),s(M(w("prefab"),w("prefab"))).toBe(!0),s(M(w("prefab"),w("vfx"))).toBe(!1),s(M({kind:"actor"},S({kind:"actor"}))).toBe(!0),s(M(S({kind:"actor"}),{kind:"actor"})).toBe(!1);const e={version:1,variables:[{name:"sequence",type:w("sequence"),defaultValue:{assetId:"sequence-1",assetType:"sequence"}}],nodes:[{id:"prefab",kind:"asset.reference",params:{reference:{assetId:"prefab-1",assetType:"prefab"}}},{id:"vfx",kind:"vfx.play",inputs:{vfx:{value:{assetId:"vfx-1",assetType:"vfx"}}}}],edges:[]};s(C(e).map(e=>e.reference.assetId)).toEqual(["sequence-1","prefab-1","vfx-1"]),s(T(e).getOutputType("prefab","value")).toEqual({kind:"asset",assetType:"prefab"}),s(T(e).getOutputType("vfx","value")).toEqual({kind:"actor",classId:"VfxActor"}),s(L(e,{resolveAssetType:e=>new Map([["sequence-1","sequence"],["prefab-1","prefab"],["vfx-1","mesh"]]).get(e)}).diagnostics).toContainEqual(s.objectContaining({code:"wrong-asset-type",nodeId:"vfx",portId:"vfx"})),s(L(e,{resolveAssetType:()=>{}}).diagnostics).toEqual(s.arrayContaining([s.objectContaining({code:"missing-asset"})]));s(L({version:1,variables:[{name:"rotation",type:{kind:"euler"},defaultValue:[0,1]}],nodes:[],edges:[]}).diagnostics).toContainEqual(s.objectContaining({code:"invalid-structure"}));const t={version:1,nodes:[{id:"spawn",kind:"actor.spawnPrefab",inputs:{location:{value:[1,2,3]}}}],edges:[]},a=D(t);s(a.nodes[0].inputs).toEqual({position:{value:[1,2,3]}}),s(t.nodes[0].inputs).toHaveProperty("location")})});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import"reflect-metadata";import{describe as a,expect as n,test as o,vi as r}from"vitest";import{Observable as i,Subject as d}from"rxjs";import{Euler as s,Group as c,MathUtils as l,Quaternion as p,Scene as u,Vector2 as m,Vector3 as g}from"three";r.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=r.fn()),e[t]),set:(e,t,a)=>(e[t]=a,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e}),"undefined"==typeof AudioBuffer&&Object.defineProperty(globalThis,"AudioBuffer",{configurable:!0,value:class{}})}),r.mock("../gameplay/actors/builtin/index.js",()=>({default:{}})),r.mock("../effects/vfx/vfx-actor.js",()=>({VfxActor:class{}})),r.mock("../effects/vfx/vfx-param.js",()=>({VisualEffect:class{}})),r.mock("../gameplay/services/render.js",()=>({ViewController:class{}})),r.mock("../rendering.js",()=>({RenderingView:class{}})),r.mock("../gameplay/services/physics/physics-system.js",()=>({PhysicsSystem:class{}}));import{Actor as h,BaseActor as v}from"../gameplay/actors/actor.js";import{actorConstructContext as y}from"../gameplay/actors/factory.js";import{ActorComponent as b}from"../gameplay/actors/component.js";import{EventGraphCallable as w,EventGraphCompiler as f,EventGraphEventSource as k,EventGraphInstance as P,EventGraphProperty as C,createDefaultEventGraphDocument as E,hasExecutableEventGraphDocument as B,validateEventGraphDocument as M}from"../gameplay/event-graph/index.js";import{World as I}from"../gameplay/services/world.js";import{Prefab as x}from"../scene/objects/prefab.js";import{SceneMaterializer as A}from"../scene/materializer.js";a("event graph compiler",()=>{o("uses connected values while preserving authored input fallbacks",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"connected",kind:"constant.number",params:{value:2}},{id:"log",kind:"debug.log",inputs:{value:O(1)}}],edges:[W("begin","then","log"),{from:L("connected"),to:{nodeId:"log",port:"value"}}]};n((new f).compile(e).beginPlay[0].source).toContain("console.log(2)"),n(e.nodes[2].inputs?.value).toEqual(O(1))}),o("uses sensible core defaults for omitted fixed-type inputs",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"multiply",kind:"math.multiply",inputs:{a:O(3)}},{id:"log",kind:"debug.log",inputs:{value:L("multiply")}}],edges:[W("begin","then","log")]};n(M(e).diagnostics).toEqual([]),n((new f).compile(e).beginPlay[0].source).toContain("(3 * 1)"),n(e.nodes[1].inputs?.b).toBeUndefined()}),o("returns validation diagnostics without throwing",()=>{const e={version:1,variables:[{name:"value",type:{kind:"number"},defaultValue:0}],nodes:[{id:"begin",kind:"event.beginPlay"},{id:"set",kind:"variable.set",params:{variable:"value"}}],edges:[W("begin","then","set")]};n(M(e).diagnostics).toContainEqual(n.objectContaining({code:"missing-input",nodeId:"set",portId:"value"}))}),o("allows execution fan-in while keeping data inputs single-source",()=>{const e={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"branch",kind:"flow.branch",inputs:{condition:O(!0)}},{id:"log",kind:"debug.log",inputs:{value:O("joined")}}],edges:[W("begin","then","branch"),W("branch","true","log"),W("branch","false","log")]};n(M(e).diagnostics).toEqual([]),n((new f).compile(e).beginPlay[0].source.match(/console\.log/g)).toHaveLength(2);const t={version:1,nodes:[{id:"one",kind:"constant.number",params:{value:1}},{id:"two",kind:"constant.number",params:{value:2}},{id:"log",kind:"debug.log"}],edges:[{from:L("one"),to:{nodeId:"log",port:"value"}},{from:L("two"),to:{nodeId:"log",port:"value"}}]};n(M(t).diagnostics).toContainEqual(n.objectContaining({code:"invalid-structure",message:n.stringContaining("has more than one connection")}))}),o("generates and executes math, component property, branch, and callable nodes",async()=>{const e=new V,t={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"component",kind:"actor.component",params:{property:"stats"},inputs:{target:L("actor")}},{id:"current",kind:"actor.getProperty",params:{property:"score"},inputs:{target:L("component")}},{id:"two",kind:"constant.number",params:{value:2}},{id:"sum",kind:"math.add",inputs:{a:L("current"),b:L("two")}},{id:"set",kind:"actor.setProperty",params:{property:"score"},inputs:{target:L("component"),value:L("sum")}},{id:"branch",kind:"flow.branch",inputs:{condition:O(!0)}},{id:"call",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("sum")}}],edges:[W("begin","then","set"),W("set","then","branch"),W("branch","true","call")]},a=(new f).compile(t);n(a.beginPlay[0].async).toBe(!1),n(a.beginPlay[0].source).toContain("runtime.setProperty"),n(a.beginPlay[0].source).toContain("if (true)"),n(a.beginPlay[0].source).toContain("runtime.callMethod");const o=S(t,new Map([["hero",e]]),e);await o.beginPlay(),n(e.stats.score).toBe(3),n(e.recorded).toEqual([5]),n(()=>o.getProperty(e,"privateValue")).toThrow("@EventGraphProperty"),n(()=>o.callMethod(e,"privateMethod",[])).toThrow("@EventGraphCallable")}),o("gets and sets actor Object3D transforms without replacing their Three.js values",async()=>{const e=new V,t={updateActorTransform:r.fn()},a=e.object.position,o=e.object.rotation,i=e.object.scale,d=S({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"position",kind:"constant.vector3",params:{value:[10,20,30]}},{id:"scale",kind:"constant.vector3",params:{value:[2,3,4]}},{id:"setPosition",kind:"actor.setProperty",params:{property:"position"},inputs:{target:L("actor"),value:L("position")}},{id:"setRotation",kind:"actor.setProperty",params:{property:"rotation"},inputs:{target:L("actor"),value:O([.1,.2,.3])}},{id:"setScale",kind:"actor.setProperty",params:{property:"scale"},inputs:{target:L("actor"),value:L("scale")}}],edges:[W("begin","then","setPosition"),W("setPosition","then","setRotation"),W("setRotation","then","setScale")]},new Map([["hero",e]]),e,void 0,t);n(d.getProperty(e,"position")).toBe(a),n(d.getProperty(e,"rotation")).toBe(o),n(d.getProperty(e,"scale")).toBe(i),await d.beginPlay(),n(e.object.position).toBe(a),n(e.object.rotation).toBe(o),n(e.object.scale).toBe(i),n(a.toArray()).toEqual([10,20,30]),n(o.toArray()).toEqual([.1,.2,.3,"XYZ"]),n(i.toArray()).toEqual([2,3,4]),n(t.updateActorTransform).toHaveBeenCalledTimes(2),n(t.updateActorTransform).toHaveBeenNthCalledWith(1,e),n(t.updateActorTransform).toHaveBeenNthCalledWith(2,e)}),o("tweens writable actor properties from frame delta time and routes completion separately",async()=>{const e=new V;e.tweenValue=2;const t=new d,a={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"tween",kind:"actor.tweenProperty",params:{property:"tweenValue",curve:"Linear"},inputs:{target:L("actor"),duration:O(1),to:O(10)}},{id:"immediate",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:O(1)}},{id:"completed",kind:"actor.callMethod",params:{method:"markCompletion",argumentCount:0},inputs:{target:L("actor")}}],edges:[W("begin","then","tween"),W("tween","then","immediate"),W("tween","completed","completed")]},o=(new f).compile(a);n(o.beginPlay[0].async).toBe(!1),n(o.beginPlay[0].source).toContain("runtime.tweenProperty(");const r=S(a,new Map([["hero",e]]),e,t);await r.beginPlay(),n(e.tweenValue).toBe(2),n(e.recorded).toEqual([1]),n(e.completionCount).toBe(0),t.next(.25),n(e.tweenValue).toBe(4),n(e.completionCount).toBe(0),t.next(.75),n(e.tweenValue).toBe(10),n(e.completionCount).toBe(1),n(t.observed).toBe(!1)}),o("updates physics on every tweened actor position change",async()=>{const e=new V,t=new d,a={updateActorTransform:r.fn()},o=S({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"tween",kind:"actor.tweenProperty",params:{property:"position",curve:"Linear"},inputs:{target:L("actor"),duration:O(1),to:{value:[10,0,0]}}}],edges:[W("begin","then","tween")]},new Map([["hero",e]]),e,t,a);await o.beginPlay(),t.next(.5),n(e.object.position.toArray()).toEqual([5,0,0]),n(a.updateActorTransform).toHaveBeenCalledTimes(2)}),o("runs local Move, Rotate, and Scale To/By actions from current transforms",async()=>{const e=new d,t={updateActorTransform:r.fn()},a=new V,o=new V,i=new V,c=new V,u=new V,m=new V;a.position.set(1,0,0),o.position.set(2,0,0),i.rotation.set(0,l.degToRad(170),0),u.object.scale.setScalar(2),m.object.scale.setScalar(2);const h=S({version:1,nodes:[],edges:[]},new Map,a,e,t);await h.beginPlay(),h.tweenMoveTo(a,new g(5,0,0),1,"Linear","local",void 0,"moveTo"),h.tweenMoveBy(o,new g(4,0,0),1,"Linear","local",void 0,"moveBy"),h.tweenRotateTo(i,new s(0,l.degToRad(-170),0),1,"Linear","local",void 0,"rotateTo"),h.tweenRotateBy(c,360,1,"Linear","local","y",void 0,"rotateBy"),h.tweenScaleTo(u,new g(6,6,6),1,"Linear",void 0,"scaleTo"),h.tweenScaleBy(m,new g(3,3,3),1,"Linear",void 0,"scaleBy"),e.next(.5),n(a.position.toArray()).toEqual([3,0,0]),n(o.position.toArray()).toEqual([4,0,0]),n(u.object.scale.toArray()).toEqual([4,4,4]),n(m.object.scale.toArray()).toEqual([4,4,4]),j(i.quaternion,(new p).setFromEuler(new s(0,Math.PI,0))),j(c.quaternion,(new p).setFromAxisAngle(new g(0,1,0),Math.PI)),e.next(.5),n(a.position.toArray()).toEqual([5,0,0]),n(o.position.toArray()).toEqual([6,0,0]),j(c.quaternion,new p),n(t.updateActorTransform).toHaveBeenCalledTimes(12)}),o("keeps world-space Move and Rotate actions in world space while parents move",async()=>{const e=new d,t=new V,a=new V,o=new V,r=new V,i=new c,u=new c,m=new c,h=new c;i.position.x=10,u.position.x=10,m.rotation.y=Math.PI/2,h.rotation.y=Math.PI/2,i.add(t.object),u.add(a.object),m.add(o.object),h.add(r.object);const v=S({version:1,nodes:[],edges:[]},new Map,t,e);await v.beginPlay(),v.tweenMoveTo(t,new g(20,0,0),1,"Linear","world",void 0,"moveTo"),v.tweenMoveBy(a,new g(4,0,0),1,"Linear","world",void 0,"moveBy"),v.tweenRotateTo(o,new s(0,Math.PI,0),1,"Linear","world",void 0,"rotateTo"),v.tweenRotateBy(r,180,1,"Linear","world","y",void 0,"rotateBy"),e.next(.5),n(t.object.getWorldPosition(new g).x).toBeCloseTo(15),n(a.object.getWorldPosition(new g).x).toBeCloseTo(12),j(o.object.getWorldQuaternion(new p),(new p).setFromAxisAngle(new g(0,1,0),l.degToRad(135))),j(r.object.getWorldQuaternion(new p),(new p).setFromAxisAngle(new g(0,1,0),Math.PI)),i.position.x=12,u.position.x=11,m.rotation.y=l.degToRad(120),h.rotation.y=l.degToRad(120),e.next(.5),n(t.object.getWorldPosition(new g).x).toBeCloseTo(20),n(a.object.getWorldPosition(new g).x).toBeCloseTo(14),j(o.object.getWorldQuaternion(new p),(new p).setFromAxisAngle(new g(0,1,0),Math.PI)),j(r.object.getWorldQuaternion(new p),(new p).setFromAxisAngle(new g(0,1,0),l.degToRad(270)))}),o("handles replacement, zero-duration completion ordering, and teardown cancellation",async()=>{const e=new d,t=new V,a=S({version:1,nodes:[],edges:[]},new Map,t,e),o=[];await a.beginPlay(),a.tweenProperty(t,"tweenValue",10,1,"Linear",()=>o.push("replaced"),"first"),a.tweenProperty(t,"tweenValue",20,1,"Linear",()=>o.push("replacement"),"second"),e.next(1),n(t.tweenValue).toBe(20),n(o).toEqual(["replacement"]),a.tweenScaleTo(t,new g(2,2,2),0,"Linear",()=>o.push("zero"),"zero"),o.push("immediate"),n(t.object.scale.toArray()).toEqual([2,2,2]),n(o).toEqual(["replacement","immediate"]),await Promise.resolve(),n(o).toEqual(["replacement","immediate","zero"]),a.tweenMoveBy(t,new g(10,0,0),1,"Linear","local",()=>o.push("ended"),"ended"),a.endPlay(),e.next(1),n(o).not.toContain("ended")}),o("materializes vector constants, inline inputs, properties, and variable defaults as fresh Three.js values",async()=>{const e=new V,t={version:1,variables:[{name:"position",type:{kind:"vector3"},defaultValue:[7,8,9]}],nodes:[{id:"begin",kind:"event.beginPlay"},{id:"observable",kind:"event.observable",params:{actorId:"hero",property:"vectorEvent"}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"vector3",kind:"constant.vector3",params:{value:[1,2,3]}},{id:"vector2",kind:"constant.vector2",params:{value:[4,5]}},{id:"position",kind:"variable.get",params:{variable:"position"}},{id:"setProperty",kind:"actor.setProperty",params:{property:"vectorProperty"},inputs:{target:L("actor"),value:L("vector3")}},{id:"first",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("vector3")}},{id:"second",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("vector3")}},{id:"inline",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:O([10,11,12])}},{id:"variable",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("position")}},{id:"capture2",kind:"actor.callMethod",params:{method:"captureVector2",argumentCount:1},inputs:{target:L("actor"),arg0:L("vector2")}},{id:"make",kind:"actor.callMethod",params:{method:"makeVector3",argumentCount:0},inputs:{target:L("actor")}},{id:"captureReturn",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("make")}},{id:"captureObservable",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:{nodeId:"observable",port:"value"}}}],edges:[W("begin","then","setProperty"),W("setProperty","then","first"),W("first","then","second"),W("second","then","inline"),W("inline","then","variable"),W("variable","then","capture2"),W("capture2","then","make"),W("make","then","captureReturn"),W("observable","then","captureObservable")]},a=S(t,new Map([["hero",e]]),e);await a.beginPlay(),n(e.vectorProperty).toBeInstanceOf(g),n(e.vectorProperty.toArray()).toEqual([1,2,3]),n(e.vectorSnapshots).toEqual([[1,2,3],[1,2,3],[10,11,12],[7,8,9],[13,14,15]]),n(e.vectorValues[0]).not.toBe(e.vectorValues[1]),n(e.vector2Values[0]).toBeInstanceOf(m),n(e.vector2Values[0].toArray()).toEqual([4,5]);const o=new g(16,17,18);e.vectorEvent.next(o),n(e.vectorSnapshots.at(-1)).toEqual([16,17,18]),n(e.vectorValues.at(-1)).toBe(o);const r=new V;await S(t,new Map([["hero",r]]),r).beginPlay(),n(r.vectorSnapshots[3]).toEqual([7,8,9])}),o("runs vector arithmetic with value semantics for graph-owned storage",async()=>{const e=new V,t={version:1,variables:[{name:"position",type:{kind:"vector3"},defaultValue:[1,2,3]}],nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"position",kind:"variable.get",params:{variable:"position"}},{id:"offset",kind:"constant.vector3",params:{value:[4,5,6]}},{id:"one",kind:"constant.vector3",params:{value:[1,1,1]}},{id:"sum",kind:"math.add",inputs:{a:L("position"),b:L("offset")}},{id:"setProperty",kind:"actor.setProperty",params:{property:"vectorProperty"},inputs:{target:L("actor"),value:L("sum")}},{id:"captureSum",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("sum")}},{id:"capturePosition",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("position")}},{id:"incremented",kind:"math.add",inputs:{a:L("position"),b:L("one")}},{id:"setVariable",kind:"variable.set",params:{variable:"position"},inputs:{value:L("incremented")}},{id:"firstVariable",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("position")}},{id:"secondVariable",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("position")}}],edges:[W("begin","then","setProperty"),W("setProperty","then","captureSum"),W("captureSum","then","capturePosition"),W("capturePosition","then","setVariable"),W("setVariable","then","firstVariable"),W("firstVariable","then","secondVariable")]};await S(t,new Map([["hero",e]]),e).beginPlay(),n(e.vectorProperty.toArray()).toEqual([5,7,9]),n(e.vectorSnapshots).toEqual([[5,7,9],[1,2,3],[2,3,4],[2,3,4]])}),o("runs vector utility nodes for common gameplay math",async()=>{const e=new V,t={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"forward",kind:"constant.vector3",params:{value:[1,0,0]}},{id:"up",kind:"constant.vector3",params:{value:[0,1,0]}},{id:"zero",kind:"constant.vector3",params:{value:[0,0,0]}},{id:"ten",kind:"constant.vector3",params:{value:[10,0,0]}},{id:"threeFour",kind:"constant.vector3",params:{value:[0,3,4]}},{id:"cross",kind:"vector.cross",inputs:{a:L("forward"),b:L("up")}},{id:"normalize",kind:"vector.normalize",inputs:{value:L("threeFour")}},{id:"lerp",kind:"vector.lerp",inputs:{a:L("zero"),b:L("ten"),alpha:O(.25)}},{id:"rotated",kind:"vector.applyRotation",inputs:{value:L("forward"),rotation:O([0,Math.PI/2,0])}},{id:"distance",kind:"vector.distance",inputs:{a:L("forward"),b:L("up")}},{id:"dot",kind:"vector.dot",inputs:{a:L("forward"),b:L("up")}},{id:"length",kind:"vector.length",inputs:{value:L("threeFour")}},{id:"captureCross",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("cross")}},{id:"captureNormalize",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("normalize")}},{id:"captureLerp",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("lerp")}},{id:"captureRotated",kind:"actor.callMethod",params:{method:"captureVector3",argumentCount:1},inputs:{target:L("actor"),arg0:L("rotated")}},{id:"recordDistance",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("distance")}},{id:"recordDot",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("dot")}},{id:"recordLength",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("length")}}],edges:[W("begin","then","captureCross"),W("captureCross","then","captureNormalize"),W("captureNormalize","then","captureLerp"),W("captureLerp","then","captureRotated"),W("captureRotated","then","recordDistance"),W("recordDistance","then","recordDot"),W("recordDot","then","recordLength")]};await S(t,new Map([["hero",e]]),e).beginPlay(),n(e.vectorSnapshots[0]).toEqual([0,0,1]),n(e.vectorSnapshots[1][0]).toBeCloseTo(0),n(e.vectorSnapshots[1][1]).toBeCloseTo(.6),n(e.vectorSnapshots[1][2]).toBeCloseTo(.8),n(e.vectorSnapshots[2]).toEqual([2.5,0,0]),n(e.vectorSnapshots[3][0]).toBeCloseTo(0),n(e.vectorSnapshots[3][1]).toBeCloseTo(0),n(e.vectorSnapshots[3][2]).toBeCloseTo(-1),n(e.recorded[0]).toBeCloseTo(Math.SQRT2),n(e.recorded[1]).toBe(0),n(e.recorded[2]).toBe(5)}),o("keeps synchronous update handlers allocation-free and owns observable subscriptions",async()=>{const e=new V,t=new d,a={version:1,nodes:[{id:"update",kind:"event.update"},{id:"observable",kind:"event.observable",params:{actorId:"hero",property:"damage"}},{id:"end",kind:"event.endPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"tick",kind:"actor.callMethod",params:{method:"tick",argumentCount:1},inputs:{target:L("actor"),arg0:{nodeId:"update",port:"deltaTime"}}},{id:"damage",kind:"actor.callMethod",params:{method:"takeDamage",argumentCount:1},inputs:{target:L("actor"),arg0:{nodeId:"observable",port:"value"}}},{id:"ended",kind:"actor.callMethod",params:{method:"graphEnded",argumentCount:0},inputs:{target:L("actor")}}],edges:[W("update","then","tick"),W("observable","then","damage"),W("end","then","ended")]},o=(new f).compile(a);n(o.update[0].async).toBe(!1),n(o.update[0].source).toContain("eventValue");const r=S(a,new Map([["hero",e]]),e,t);await r.beginPlay(),t.next(.25),e.damage.next(7),n(e.deltaTimes).toEqual([.25]),n(e.damageTaken).toEqual([7]),r.endPlay(),t.next(.5),e.damage.next(9),n(e.deltaTimes).toEqual([.25]),n(e.damageTaken).toEqual([7]),n(e.graphEndCount).toBe(1)}),o("subscribes static event sources and routes emitted values through event pins",async()=>{const e=new V,t={version:1,nodes:[{id:"source",kind:"event.source",params:{actorId:"hero",source:"onNumberEvent"}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"record",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:{nodeId:"source",port:"value"}}}],edges:[W("source","then","record")]},a=(new f).compile(t,{resolveActorClass:e=>"hero"===e?V:void 0});n(a.eventSources).toHaveLength(1),n(a.eventSources[0]).toMatchObject({actorId:"hero",method:"onNumberEvent"});const o=S(t,new Map([["hero",e]]),e);await o.beginPlay(),e.numberEvent.next(12),n(e.recorded).toEqual([12]),o.endPlay(),e.numberEvent.next(13),n(e.recorded).toEqual([12])}),o("binds runtime event sources once per node and replaces subscriptions on rebind",async()=>{const e=new V,t=new d,a={version:1,nodes:[{id:"update",kind:"event.update"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"bind",kind:"event.bindSource",params:{source:"onNumberEvent",argumentCount:0},inputs:{target:L("actor")}},{id:"immediate",kind:"actor.callMethod",params:{method:"markCompletion",argumentCount:0},inputs:{target:L("actor")}},{id:"record",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:{nodeId:"bind",port:"value"}}}],edges:[W("update","then","bind"),W("bind","then","immediate"),W("bind","triggered","record")]},o=(new f).compile(a,{resolveActorClass:e=>"hero"===e?V:void 0});n(o.update[0].source).toContain("runtime.bindEventSource");const r=S(a,new Map([["hero",e]]),e,t);await r.beginPlay(),t.next(.016),t.next(.016),n(e.completionCount).toBe(2),e.numberEvent.next(7),n(e.recorded).toEqual([7]),r.endPlay(),e.numberEvent.next(8),n(e.recorded).toEqual([7])}),o("awaits actor class spawn nodes before continuing execution",async()=>{const e=new V,t=new q,a=r.fn(async()=>t),o={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"spawn",kind:"actor.spawnClass",params:{classId:"SpawnedGraphActor"}},{id:"mark",kind:"actor.callMethod",params:{method:"mark",argumentCount:0},inputs:{target:L("spawn")}}],edges:[W("begin","then","spawn"),W("spawn","then","mark")]},i=(new f).compile(o);n(i.beginPlay[0].async).toBe(!0),n(i.beginPlay[0].source).toContain("await runtime.spawnActor");const d=new P(o,{world:{spawnActor:a},actorsById:new Map([["owner",e]]),mainActor:e});await d.beginPlay(),n(a).toHaveBeenCalledOnce(),n(t.marked).toBe(!0)}),o("finds a registered actor type through a statically selected class input",async()=>{const e=new V,t=new q,a=r.fn(()=>t),o={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"find",kind:"actor.findByType",inputs:{actorClass:{value:"SpawnedGraphActor"}}},{id:"valid",kind:"flow.isValid",inputs:{value:L("find")}},{id:"mark",kind:"actor.callMethod",params:{method:"mark",argumentCount:0},inputs:{target:L("valid")}}],edges:[W("begin","then","valid"),W("valid","valid","mark")]},i=new P(o,{world:{spawnActor:r.fn(),findActorByType:a},actorsById:new Map([["owner",e]]),mainActor:e});await i.beginPlay(),n(a).toHaveBeenCalledWith(q),n(t.marked).toBe(!0)}),o("plays typed transient assets, auto-destroys on completion, and preserves spawned prefabs",async()=>{const e=new V,t=new V,a=new V,o=new d,i=new d,c={id:"spawned-prefab"},l={spawnPrefab:r.fn(async()=>({instance:c,mainActor:null})),playVfx:r.fn(async()=>({actor:t,completed:o})),playSequence:r.fn(async()=>({actor:a,completed:i})),destroyPrefab:r.fn(),destroyActor:r.fn()},p={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"vfx",kind:"vfx.play",inputs:{vfx:{value:{assetId:"vfx-1",assetType:"vfx"}}}},{id:"sequence",kind:"sequence.play",inputs:{sequence:{value:{assetId:"sequence-1",assetType:"sequence"}}}},{id:"prefab",kind:"actor.spawnPrefab",inputs:{prefab:{value:{assetId:"prefab-1",assetType:"prefab"}}}},{id:"owner",kind:"actor.reference",params:{actorId:"$self"}},{id:"completed",kind:"actor.callMethod",params:{method:"markCompletion",argumentCount:0},inputs:{target:L("owner")}}],edges:[W("begin","then","vfx"),W("vfx","then","sequence"),W("vfx","completed","completed"),W("sequence","then","prefab")]},u=new P(p,{world:{spawnActor:r.fn()},assets:l,actorsById:new Map,mainActor:e});await u.beginPlay(),n(l.playVfx).toHaveBeenCalledWith("vfx-1",n.any(g),n.any(s)),n(l.playSequence).toHaveBeenCalledWith("sequence-1",e,null,!1),n(l.spawnPrefab).toHaveBeenCalledWith("prefab-1",n.any(g),n.any(s)),n(e.completionCount).toBe(0),o.next(),await new Promise(e=>queueMicrotask(e)),n(e.completionCount).toBe(1),n(l.destroyActor).toHaveBeenCalledWith(t),u.endPlay(),i.next(),n(e.completionCount).toBe(1),n(l.destroyActor).toHaveBeenCalledWith(a),n(l.destroyPrefab).not.toHaveBeenCalled()}),o("destroys transient asset handles that finish loading after graph teardown",async()=>{const e=new V;let t;const a=new Promise(e=>{t=e}),o={spawnPrefab:r.fn(),playVfx:r.fn(()=>a),playSequence:r.fn(),destroyPrefab:r.fn(),destroyActor:r.fn()},i={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"vfx",kind:"vfx.play",inputs:{vfx:{value:{assetId:"vfx-1",assetType:"vfx"}}}}],edges:[W("begin","then","vfx")]},d=new P(i,{world:{spawnActor:r.fn()},assets:o,actorsById:new Map}),s=d.beginPlay();d.endPlay(),t({actor:e}),await n(s).rejects.toThrow("Event graph execution was cancelled"),n(o.destroyActor).toHaveBeenCalledWith(e)}),o("persists graph variables across synchronous update executions",async()=>{const e=new V,t=new d,a={version:1,variables:[{name:"count",defaultValue:0}],nodes:[{id:"update",kind:"event.update"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"count",kind:"variable.get",params:{variable:"count"}},{id:"one",kind:"constant.number",params:{value:1}},{id:"incremented",kind:"math.add",inputs:{a:L("count"),b:L("one")}},{id:"set",kind:"variable.set",params:{variable:"count"},inputs:{value:L("incremented")}},{id:"record",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("count")}}],edges:[W("update","then","set"),W("set","then","record")]},o=(new f).compile(a);n(o.update[0].async).toBe(!1),n(o.update[0].source).toContain("runtime.getVariable"),n(o.update[0].source).toContain("runtime.setVariable");const r=S(a,new Map([["hero",e]]),e,t);await r.beginPlay(),t.next(.1),t.next(.1),n(e.recorded).toEqual([1,2])}),o("lowers parallel branches and delays through the structured flow compiler",async()=>{const e=new V,t={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"parallel",kind:"flow.parallel",params:{ports:["delayed","immediate"]}},{id:"delay",kind:"flow.delay",inputs:{durationMs:O(1)}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"delayedValue",kind:"constant.number",params:{value:1}},{id:"immediateValue",kind:"constant.number",params:{value:2}},{id:"doneValue",kind:"constant.number",params:{value:3}},{id:"recordDelayed",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("delayedValue")}},{id:"recordImmediate",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("immediateValue")}},{id:"recordDone",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("doneValue")}}],edges:[W("begin","then","parallel"),W("parallel","delayed","delay"),W("delay","then","recordDelayed"),W("parallel","immediate","recordImmediate"),W("parallel","then","recordDone")]},a=(new f).compile(t);n(a.beginPlay[0].async).toBe(!0),n(a.beginPlay[0].source).toContain("await Promise.all"),n(a.beginPlay[0].source).toContain("runtime.delay(1)");const o=S(t,new Map([["hero",e]]),e);await o.beginPlay(),n(e.recorded).toEqual([2,1,3])}),o("runs Delay through the game-time timer",async()=>{const e=new V,t=new d,a={setInterval:r.fn(()=>1),clearInterval:r.fn(),createTimer:r.fn(()=>t)},o={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"delay",kind:"flow.delay",inputs:{durationMs:O(250)}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"record",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:O(1)}}],edges:[W("begin","then","delay"),W("delay","then","record")]},i=new P(o,{world:{spawnActor:r.fn()},actorsById:new Map([["hero",e]]),mainActor:e,timer:a}).beginPlay();n(a.createTimer).toHaveBeenCalledWith(250),n(e.recorded).toEqual([]),t.next(),t.complete(),await i,n(e.recorded).toEqual([1])}),o("owns game-time intervals and clears them when the graph ends",async()=>{const e=new V;let t;const a={setInterval:r.fn(e=>(t=e,42)),clearInterval:r.fn()},o={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"interval",kind:"flow.interval",inputs:{intervalMs:O(250)}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"tick",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:O(1)}},{id:"started",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:O(2)}}],edges:[W("begin","then","interval"),W("interval","interval","tick"),W("interval","then","started")]},i=new P(o,{world:{spawnActor:r.fn()},actorsById:new Map([["hero",e]]),mainActor:e,timer:a});await i.beginPlay(),n(a.setInterval).toHaveBeenCalledWith(n.any(Function),250,e),n(e.recorded).toEqual([2]),t?.(),n(e.recorded).toEqual([2,1]),i.endPlay(),n(a.clearInterval).toHaveBeenCalledWith(42)}),o("shares Do Once and Gate state across execution input entry points",async()=>{const e=new V,t=S({version:1,nodes:[{id:"onceFirst",kind:"event.beginPlay"},{id:"onceReset",kind:"event.beginPlay"},{id:"onceSecond",kind:"event.beginPlay"},{id:"gateClose",kind:"event.beginPlay"},{id:"gateBlocked",kind:"event.beginPlay"},{id:"gateOpen",kind:"event.beginPlay"},{id:"gateAllowed",kind:"event.beginPlay"},{id:"once",kind:"flow.doOnce"},{id:"gate",kind:"flow.gate"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"onceRecord",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:O(1)}},{id:"gateRecord",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:O(2)}}],edges:[W("onceFirst","then","once"),{from:{nodeId:"onceReset",port:"then"},to:{nodeId:"once",port:"reset"}},W("onceSecond","then","once"),W("once","then","onceRecord"),{from:{nodeId:"gateClose",port:"then"},to:{nodeId:"gate",port:"close"}},{from:{nodeId:"gateBlocked",port:"then"},to:{nodeId:"gate",port:"enter"}},{from:{nodeId:"gateOpen",port:"then"},to:{nodeId:"gate",port:"open"}},{from:{nodeId:"gateAllowed",port:"then"},to:{nodeId:"gate",port:"enter"}},W("gate","exit","gateRecord")]},new Map([["hero",e]]),e);await t.beginPlay(),n(e.recorded).toEqual([1,1,2])}),o("iterates arrays in order and continues after the final element",async()=>{const e=new V,t=S({version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"forEach",kind:"flow.forEach",inputs:{array:O([4,7])}},{id:"recordElement",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("forEach","arrayElement")}},{id:"recordIndex",kind:"actor.callMethod",params:{method:"recordIndex",argumentCount:1},inputs:{target:L("actor"),arg0:L("forEach","arrayIndex")}},{id:"completed",kind:"actor.callMethod",params:{method:"markCompletion",argumentCount:0},inputs:{target:L("actor")}}],edges:[W("begin","then","forEach"),W("forEach","loopBody","recordElement"),W("recordElement","then","recordIndex"),W("forEach","completed","completed")]},new Map([["hero",e]]),e);await t.beginPlay(),n(e.recorded).toEqual([4,7]),n(e.recordedIndexes).toEqual([0,1]),n(e.completionCount).toBe(1)}),o("cancels delayed update continuations when the graph ends",async()=>{r.useFakeTimers();try{const e=new V,t=new d,a=r.fn(),o={version:1,nodes:[{id:"update",kind:"event.update"},{id:"delay",kind:"flow.delay",inputs:{durationMs:O(100)}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"value",kind:"constant.number",params:{value:1}},{id:"record",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("value")}}],edges:[W("update","then","delay"),W("delay","then","record")]},i=new P(o,{world:{spawnActor:r.fn()},actorsById:new Map([["hero",e]]),mainActor:e,updates:t,timer:F(),onError:a});await i.beginPlay(),t.next(.1),i.endPlay(),await r.runAllTimersAsync(),n(e.recorded).toEqual([]),n(a).not.toHaveBeenCalled()}finally{r.useRealTimers()}}),o("lowers switch and callable error routes through structured compiler routes",async()=>{const e=new V,t={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"switch",kind:"flow.switch",params:{cases:[{value:"a",port:"a"},{value:"b",port:"b"}]},inputs:{value:O("b")}},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"one",kind:"constant.number",params:{value:1}},{id:"two",kind:"constant.number",params:{value:2}},{id:"three",kind:"constant.number",params:{value:3}},{id:"recordA",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("one")}},{id:"recordB",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("two")}},{id:"tryCall",kind:"actor.tryCallMethod",params:{method:"fail",argumentCount:0},inputs:{target:L("actor")}},{id:"markFailure",kind:"actor.callMethod",params:{method:"markFailure",argumentCount:0},inputs:{target:L("actor")}},{id:"recordDone",kind:"actor.callMethod",params:{method:"record",argumentCount:1},inputs:{target:L("actor"),arg0:L("three")}}],edges:[W("begin","then","switch"),W("switch","a","recordA"),W("switch","b","recordB"),W("switch","then","tryCall"),W("tryCall","error","markFailure"),W("tryCall","then","recordDone")]},a=(new f).compile(t);n(a.beginPlay[0].source).toContain('switch ("b")'),n(a.beginPlay[0].source).toContain("try {"),n(a.beginPlay[0].source).toContain("catch (caught_");const o=S(t,new Map([["hero",e]]),e);await o.beginPlay(),n(e.recorded).toEqual([2,3]),n(e.failureCount).toBe(1)})}),o("World owns a prefab event graph from actor begin play through actor teardown",async()=>{const e=new V,t=new d,a=[];e.lifecycle=a;const o={id:"prefab",name:"Prefab",type:"prefab",prefab:{objects:[],mainActorId:"hero",eventGraph:{version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"end",kind:"event.endPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"graphBegin",kind:"actor.callMethod",params:{method:"graphBegin",argumentCount:0},inputs:{target:L("actor")}},{id:"graphEnd",kind:"actor.callMethod",params:{method:"graphEnd",argumentCount:0},inputs:{target:L("actor")}}],edges:[W("begin","then","graphBegin"),W("end","then","graphEnd")]}}},i=new c,s=R({inEditor:!0,setScene:r.fn(),createFromPrefabAsset:r.fn(async()=>({object:i,actors:[e],actorsById:new Map([["hero",e]]),mainActor:e}))},t),l=await s.spawnPrefab(new x(o));n(a).toEqual(["actor-begin","graph-begin"]),s.removePrefab(l),n(a).toEqual(["actor-begin","graph-begin","graph-end","actor-end"])}),o("World skips prefab event graphs with no connected event execution outputs",async()=>{const e=new V,t=new d,a=[];e.lifecycle=a;const o=E(),i={id:"prefab",name:"Prefab",type:"prefab",prefab:{objects:[],mainActorId:"hero",eventGraph:o}},s=R({inEditor:!0,setScene:r.fn(),createFromPrefabAsset:r.fn(async()=>({object:new c,actors:[e],actorsById:new Map([["hero",e]]),mainActor:e}))},t),l=await s.spawnPrefab(new x(i));n(B(o)).toBe(!1),n(l.eventGraph).toBeUndefined(),n(a).toEqual(["actor-begin"]),s.removePrefab(l),n(a).toEqual(["actor-begin","actor-end"])}),o("SceneMaterializer collects executable scene prefab graphs but excludes no-op and World runtime spawns",async()=>{const e=function(){const e={getObjects:()=>[],onCreate:r.fn(),onUpdate:r.fn(),onRemove:r.fn()},t={onCreate:new d,onUpdate:new d};return new A(new u,e,t,{},{},[],[],{create:r.fn(),initActor:r.fn()})}();e.inEditor=!1;const t={version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"log",kind:"debug.log"}],edges:[W("begin","then","log")]},a=E(),o={id:"decoration",name:"Decoration",type:"prefab",prefab:{objects:[],eventGraph:a}},i={id:"interactable",name:"Interactable",type:"prefab",prefab:{objects:[],eventGraph:t}};await e.createFromPrefabAsset(i,{sceneObjectChain:["placed-interactable"]}),await e.createFromPrefabAsset(i,{sceneObjectChain:["runtime-interactable"],runtimeSpawn:!0}),await e.createFromPrefabAsset(o,{sceneObjectChain:["placed-decoration"]}),n(B(t)).toBe(!0),n(B(a)).toBe(!1),n(e.prefabEventGraphInstances).toHaveLength(1),n(e.prefabEventGraphInstances[0].id).toBe("placed-interactable"),n(e.prefabEventGraphInstances[0].graph).toBe(t)}),o("World owns scene-materialized prefab graphs around actor lifetime",async()=>{const e=new V,t=new d,a=[];e.lifecycle=a;const o={id:"scene/interactable",graph:{version:1,nodes:[{id:"begin",kind:"event.beginPlay"},{id:"end",kind:"event.endPlay"},{id:"actor",kind:"actor.reference",params:{actorId:"hero"}},{id:"graphBegin",kind:"actor.callMethod",params:{method:"graphBegin",argumentCount:0},inputs:{target:L("actor")}},{id:"graphEnd",kind:"actor.callMethod",params:{method:"graphEnd",argumentCount:0},inputs:{target:L("actor")}}],edges:[W("begin","then","graphBegin"),W("end","then","graphEnd")]},object:new c,actors:[e],actorsById:new Map([["hero",e]]),mainActor:e},r=new d,i=new d,s={prefabEventGraphAdded$:r,prefabEventGraphRemoved$:i,prefabEventGraphInstances:[o]},l=R({},t);await l.startSceneEventGraphs(s),n(a).toEqual(["actor-begin","graph-begin"]),i.next(o),n(a).toEqual(["actor-begin","graph-begin","graph-end","actor-end"]),l.stopSceneEventGraphs()});class T extends b{constructor(){super(...arguments),this.score=1}}e([C(),t("design:type",Object)],T.prototype,"score",void 0);let V=class extends v{constructor(){super(),this.stats=new T,this.damage=new d,this.privateValue=5,this.recorded=[],this.recordedIndexes=[],this.deltaTimes=[],this.damageTaken=[],this.graphEndCount=0,this.failureCount=0,this.completionCount=0,this.vectorValues=[],this.vectorSnapshots=[],this.vector2Values=[],this.vectorProperty=new g,this.tweenValue=0,this.vectorEvent=new d,this.numberEvent=new d,this.stats.actor=this,y.actor=null}onBeginPlay(){this.lifecycle?.push("actor-begin")}onEndPlay(){this.lifecycle?.push("actor-end")}record(e){this.recorded.push(e)}recordIndex(e){this.recordedIndexes.push(e)}tick(e){this.deltaTimes.push(e)}takeDamage(e){this.damageTaken.push(e)}graphEnded(){this.graphEndCount++}graphBegin(){this.lifecycle?.push("graph-begin")}graphEnd(){this.lifecycle?.push("graph-end")}fail(){throw new Error("expected graph test failure")}markFailure(){this.failureCount++}markCompletion(){this.completionCount++}privateMethod(){}captureVector3(e){this.vectorValues.push(e),this.vectorSnapshots.push(e.toArray()),e.set(99,99,99)}captureVector2(e){this.vector2Values.push(e)}makeVector3(){return new g(13,14,15)}onNumberEvent(){return this.numberEvent}};e([C(),t("design:type",Object)],V.prototype,"damage",void 0),e([C({type:g}),t("design:type",Object)],V.prototype,"vectorProperty",void 0),e([C({type:Number}),t("design:type",Object)],V.prototype,"tweenValue",void 0),e([C({observableValueType:g,writable:!1}),t("design:type",Object)],V.prototype,"vectorEvent",void 0),e([w(),t("design:type",Function),t("design:paramtypes",[Number]),t("design:returntype",void 0)],V.prototype,"record",null),e([w(),t("design:type",Function),t("design:paramtypes",[Number]),t("design:returntype",void 0)],V.prototype,"recordIndex",null),e([w(),t("design:type",Function),t("design:paramtypes",[Number]),t("design:returntype",void 0)],V.prototype,"tick",null),e([w(),t("design:type",Function),t("design:paramtypes",[Number]),t("design:returntype",void 0)],V.prototype,"takeDamage",null),e([w(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],V.prototype,"graphEnded",null),e([w(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],V.prototype,"graphBegin",null),e([w(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],V.prototype,"graphEnd",null),e([w(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],V.prototype,"fail",null),e([w(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],V.prototype,"markFailure",null),e([w(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],V.prototype,"markCompletion",null),e([w({parameters:[{name:"value",type:g}]}),t("design:type",Function),t("design:paramtypes",[g]),t("design:returntype",void 0)],V.prototype,"captureVector3",null),e([w({parameters:[{name:"value",type:m}]}),t("design:type",Function),t("design:paramtypes",[m]),t("design:returntype",void 0)],V.prototype,"captureVector2",null),e([w({returns:g}),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",g)],V.prototype,"makeVector3",null),e([k({label:"On Number Event",emits:Number}),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],V.prototype,"onNumberEvent",null),V=e([h({typeId:"event-graph-test.runtime-actor"}),t("design:paramtypes",[])],V);let q=class extends v{constructor(){super(),this.marked=!1,y.actor=null}mark(){this.marked=!0}};function j(e,t){n(Math.abs(e.dot(t))).toBeCloseTo(1,5)}function S(e,t,a,n,o){return new P(e,{world:{spawnActor:r.fn()},actorsById:t,mainActor:a,updates:n,timer:F(),physics:o})}function F(){return{setInterval:(e,t)=>window.setInterval(e,t),clearInterval:e=>window.clearInterval(e),createTimer:e=>new i(t=>{const a=setTimeout(()=>{t.next(),t.complete()},e);return()=>clearTimeout(a)})}}function R(e,t){const a=Object.create(I.prototype);return a.scene=new u,a.actors=[],a.actorAdded=new d,a.actorRemoved=new d,a.actorFactory={inEditor:!1},a.materializer=e,a.sceneEventGraphs=new Map,a.sceneEventGraphSubscriptions=[],a.physics={addFromScene:r.fn(),removeActor:r.fn(),removeRemoved:r.fn()},a.viewController={onUpdate:()=>t},a}function L(e,t="value"){return{nodeId:e,port:t}}function O(e){return{value:e}}function W(e,t,a){return{from:{nodeId:e,port:t},to:{nodeId:a,port:"exec"}}}e([w(),t("design:type",Function),t("design:paramtypes",[]),t("design:returntype",void 0)],q.prototype,"mark",null),q=e([h(),t("design:paramtypes",[])],q);/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{expect as t,test as e}from"vitest";import{ActionInput as o,ButtonInput as a,ToggleInput as i}from"../gameplay/input/input.js";e("button input uses hold mode by default",()=>{const e=new a,o=[];e.onStart(()=>o.push(e.activated)),e.onEnd(()=>o.push(e.activated)),e.toggle(!0),t(e.activated).toBe(!0),e.toggle(!0),t(o).toEqual([!0]),e.toggle(!1),t(e.activated).toBe(!1),t(o).toEqual([!0,!1])}),e("button input can switch to toggle mode at runtime",()=>{const e=new a,o=[];e.onStart(()=>o.push(e.activated)),e.onEnd(()=>o.push(e.activated)),e.mode="toggle",e.toggle(!0),t(e.activated).toBe(!1),e.toggle(!1),t(e.activated).toBe(!0),e.toggle(!1),t(e.activated).toBe(!1),t(o).toEqual([!0,!1])}),e("action and toggle inputs remain compatibility presets",()=>{const e=new o;e.toggle(!0),t(e.activated).toBe(!0),e.toggle(!1),t(e.activated).toBe(!1);const a=new i;a.toggle(!0),t(a.activated).toBe(!1),a.toggle(!1),t(a.activated).toBe(!0)});/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{beforeAll as e,describe as t,expect as o,test as a}from"vitest";import{CharacterMovementMode as n}from"../gameplay/actors/builtin/components/character/modes.js";let r
|
|
1
|
+
import{beforeAll as e,describe as t,expect as o,test as a}from"vitest";import{CharacterMovementMode as n}from"../gameplay/actors/builtin/components/character/modes.js";let c,r;function s(e={}){return{sequence:1,clientTime:.016,dt:.016,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0,...e}}function i(e={}){return{sequence:0,x:0,y:0,z:0,velocityX:0,velocityY:0,velocityZ:0,yaw:0,mode:n.walking,flags:0,horizontalSpeed:0,...e}}function l(e){return{directionInput:{},jumpInput:{},sprintInput:{},rotationInput:{},setRootMotionAction(){},applyImpulse(){},...e}}e(async()=>{"undefined"!=typeof HTMLCanvasElement&&Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>({fillStyle:"",fillRect(){},clearRect(){},getImageData:()=>({data:new Uint8ClampedArray(4)}),putImageData(){},createImageData:()=>({data:new Uint8ClampedArray(4)}),setTransform(){},drawImage(){},save(){},restore(){},beginPath(){},moveTo(){},lineTo(){},closePath(){},stroke(){},translate(){},scale(){},rotate(){},arc(){},fill(){},measureText:()=>({width:0}),transform(){},rect(){},clip(){}})}),c=await import("../gameplay/actors/builtin/components/character/net-character-movement-protocol.js"),r=(await import("../gameplay/actors/builtin/components/character/character-movement-like.js")).getCharacterMovementLike}),t("net character movement packets",()=>{a("round trips batched saved moves",()=>{const e=[s({sequence:1,dt:.016,inputX:.25,inputY:1,yaw:.5,flags:c.MOVE_FLAG_SPRINT|c.MOVE_FLAG_CROUCH,clientX:1,clientY:2,clientZ:3}),s({sequence:2,dt:.033,inputX:-.5,inputY:.5,yaw:-1,flags:1,clientX:4,clientY:5,clientZ:6,rootMotionZ:.2})],t=c.decodeNetCharacterMoveBatch(c.encodeNetCharacterMoveBatch(e));o(t.ok).toBe(!0),t.ok&&(o(t.value.moves).toHaveLength(2),o(t.value.moves[0].sequence).toBe(1),o(t.value.moves[0].clientTime).toBeCloseTo(.016,3),o(t.value.moves[0].dt).toBeCloseTo(.016,3),o(t.value.moves[0].inputX).toBeCloseTo(.25,4),o(t.value.moves[0].flags).toBe(c.MOVE_FLAG_SPRINT|c.MOVE_FLAG_CROUCH),o(t.value.moves[1].rootMotionZ).toBeCloseTo(.2))}),a("round trips owner ack, correction, and simulated state packets",()=>{const e=i({sequence:42,x:10,y:2,z:-3,velocityX:1,yaw:1.25,mode:n.falling,flags:c.SNAPSHOT_FLAG_CROUCHING,horizontalSpeed:7}),t=c.decodeNetCharacterOwnerAck(c.encodeNetCharacterOwnerAck(42)),a=c.decodeNetCharacterOwnerCorrection(c.encodeNetCharacterOwnerCorrection(e)),r=c.decodeNetCharacterSimulatedState(c.encodeNetCharacterSimulatedState(e));o(t.ok&&t.value.sequence).toBe(42),o(a.ok&&a.value.snapshot.sequence).toBe(42),o(a.ok&&a.value.snapshot.flags).toBe(c.SNAPSHOT_FLAG_CROUCHING),o(r.ok&&r.value.mode).toBe(n.falling),o(r.ok&&r.value.flags).toBe(c.SNAPSHOT_FLAG_CROUCHING),o(r.ok&&r.value.horizontalSpeed).toBeCloseTo(7)}),a("rejects malformed, unsupported version, and wrong-kind packets",()=>{const e=c.encodeNetCharacterMoveBatch([s({sequence:1})]),t=e.slice();t[0]=99;const a=e.slice();a[1]=99,o(c.decodeNetCharacterMoveBatch(new Uint8Array([1,1,0]))).toMatchObject({ok:!1,reason:"malformed"}),o(c.decodeNetCharacterMoveBatch(t)).toMatchObject({ok:!1,reason:"unsupported-version"}),o(c.decodeNetCharacterMoveBatch(a)).toMatchObject({ok:!1,reason:"wrong-kind"})})}),t("net character prediction helpers",()=>{a("combines adjacent equivalent saved moves by default",()=>{const e=new c.NetCharacterSavedMoveBuffer(4);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1,clientZ:.1})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,clientZ:.3}));const t=e.getMovesForSend(4);o(t).toHaveLength(1),o(t[0].sequence).toBe(2),o(t[0].dt).toBeCloseTo(.032),o(t[0].clientZ).toBeCloseTo(.3)}),a("keeps adjacent saved moves separate when combining is disabled",()=>{const e=new c.NetCharacterSavedMoveBuffer(4,-1);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1,clientZ:.1})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,clientZ:.3}));const t=e.getMovesForSend(4);o(t.map(e=>e.sequence)).toEqual([1,2]),o(t.map(e=>e.dt)).toEqual([.016,.016])}),a("preserves a sprint start move for server simulation and replay",()=>{const e=new c.NetCharacterSavedMoveBuffer(4),t=c.MOVE_FLAG_SPRINT|c.MOVE_FLAG_SPRINT_START;e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1,flags:t})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,flags:c.MOVE_FLAG_SPRINT}));const a=c.encodeNetCharacterMoveBatch(e.getMovesForSend(4)),n=c.decodeNetCharacterMoveBatch(a);o(n.ok).toBe(!0),n.ok&&(o(n.value.moves.map(e=>e.sequence)).toEqual([1,2]),o(n.value.moves[0].flags).toBe(t))}),a("does not combine saved moves across crouch changes",()=>{const e=new c.NetCharacterSavedMoveBuffer(4);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,flags:c.MOVE_FLAG_CROUCH}));const t=e.getMovesForSend(4);o(t.map(e=>e.sequence)).toEqual([1,2]),o(t.map(e=>e.flags)).toEqual([0,c.MOVE_FLAG_CROUCH])}),a("combines adjacent crouched saved moves",()=>{const e=new c.NetCharacterSavedMoveBuffer(4);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1,flags:c.MOVE_FLAG_CROUCH})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1,flags:c.MOVE_FLAG_CROUCH}));const t=e.getMovesForSend(4);o(t).toHaveLength(1),o(t[0].sequence).toBe(2),o(t[0].flags).toBe(c.MOVE_FLAG_CROUCH)}),a("respects saved move max combined delta time",()=>{const e=new c.NetCharacterSavedMoveBuffer(4,.02);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1})),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1})),o(e.getMovesForSend(4).map(e=>e.sequence)).toEqual([1,2])}),a("does not combine a move after it has been selected for sending",()=>{const e=new c.NetCharacterSavedMoveBuffer(4,.1);e.push(s({sequence:1,clientTime:.016,dt:.016,inputY:1})),o(e.getMovesForSend(4).map(e=>e.sequence)).toEqual([1]),e.push(s({sequence:2,clientTime:.032,dt:.016,inputY:1}));const t=e.getMovesForSend(4);o(t.map(e=>e.sequence)).toEqual([1,2]),o(t.map(e=>e.dt)).toEqual([.016,.016])}),a("selects the oldest unacked move and newest moves for send packets",()=>{const e=new c.NetCharacterSavedMoveBuffer(8);for(let t=1;t<=5;t++)e.push(s({sequence:t,clientTime:.02*t,dt:.02,inputX:t%2==0?.25:-.25}));o(e.getMovesForSend(3).map(e=>e.sequence)).toEqual([1,4,5])}),a("replays saved moves with a deterministic simulator",()=>{const e=c.replayNetCharacterSavedMoves({x:0},[s({sequence:1,dt:.1,inputY:1}),s({sequence:2,dt:.2,inputY:1})],(e,t)=>({x:e.x+t.inputY*t.dt*10}));o(e.x).toBeCloseTo(3)}),a("validates move sequence, dt, and normalized input",()=>{o(c.validateNetCharacterMove(s({sequence:2,dt:.016}),1)).toBe(!0),o(c.validateNetCharacterMove(s({sequence:1,dt:.016}),1)).toBe(!1),o(c.validateNetCharacterMove(s({sequence:2,clientTime:0}),1)).toBe(!1),o(c.validateNetCharacterMove(s({sequence:2,dt:.5}),1,.1)).toBe(!1),o(c.validateNetCharacterMove(s({sequence:2,inputX:1,inputY:1}),1)).toBe(!1),o(c.validateNetCharacterMove(s({sequence:2,flags:128}),1)).toBe(!1)}),a("derives server move dt from client timestamps",()=>{const e=c.createNetCharacterServerMoveTimingState();c.accrueNetCharacterServerMoveTime(e,.05);const t=c.consumeNetCharacterServerMoveTime(e,s({sequence:1,clientTime:.016}),{maxMoveDeltaTime:.1}),a=c.consumeNetCharacterServerMoveTime(e,s({sequence:2,clientTime:.05}),{maxMoveDeltaTime:.1});o(t).toBeCloseTo(.016),o(a).toBeCloseTo(.034),o(e.lastClientTime).toBeCloseTo(.05)}),a("clamps server move dt and rejects clients too far ahead of server time",()=>{const e=c.createNetCharacterServerMoveTimingState();c.accrueNetCharacterServerMoveTime(e,.02);const t=c.consumeNetCharacterServerMoveTime(e,s({sequence:1,clientTime:.5}),{maxMoveDeltaTime:.05,maxServerMoveDeltaTimeScalar:2,maxClientTimeAhead:.1}),a=c.consumeNetCharacterServerMoveTime(e,s({sequence:2,clientTime:.7}),{maxMoveDeltaTime:.05,maxServerMoveDeltaTimeScalar:2,maxClientTimeAhead:.01});o(t).toBeCloseTo(.1),o(a).toBe(-1)})}),t("net character simulated proxy smoothing",()=>{a("interpolates delayed snapshots",()=>{const e=new c.NetCharacterProxySmoother(.1,20),t=i();e.push(i({sequence:1,x:0}),0),e.push(i({sequence:2,x:10}),1),o(e.sample(.6,t)).toBe(!0),o(t.x).toBeCloseTo(5)}),a("snaps instead of interpolating large gaps",()=>{const e=new c.NetCharacterProxySmoother(0,1),t=i();e.push(i({sequence:1,x:0}),0),e.push(i({sequence:2,x:10}),1),o(e.sample(.5,t)).toBe(!0),o(t.x).toBe(10)})}),t("character movement compatibility",()=>{a("prefers the default movement component when present",()=>{const e=l({horizontalSpeed:2}),t=l({horizontalSpeed:5,isDefaultCharacterMovementComponent:!0});o(r({oldMovement:e,defaultMovement:t,attachedComponents:[]})).toBe(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 e,__metadata as a}from"tslib";import{describe as t,expect as
|
|
1
|
+
import{__decorate as e,__metadata as a}from"tslib";import{describe as t,expect as r,it as n,vi as o}from"vitest";import{Scene as i}from"three";import{Subject as s}from"rxjs";o.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,a)=>(a in e||(e[a]=("string"!=typeof a||!a.startsWith("is"))&&o.fn()),e[a]),set:(e,a,t)=>(e[a]=t,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e}),"undefined"==typeof AudioBuffer&&Object.defineProperty(globalThis,"AudioBuffer",{configurable:!0,value:class{}})}),o.mock("../gameplay/actors/builtin/index.js",()=>({default:{}})),o.mock("../effects/vfx/vfx-actor.js",()=>({VfxActor:class{}})),o.mock("../effects/vfx/vfx-param.js",()=>({VisualEffect:class{}})),o.mock("../rendering.js",()=>({RenderingView:class{},setRenderingPaused:o.fn()}));import{BaseActor as c}from"../gameplay/actors/actor.js";import{ActorComponent as p}from"../gameplay/actors/component.js";import{Parameter as m}from"../shader/parameter.js";import{SceneMaterializer as l}from"../scene/materializer.js";import{SerializedParamType as u}from"../scene/model.js";class f extends p{constructor(){super(...arguments),this.animationPreset="mixamo"}}e([m(),a("design:type",Object)],f.prototype,"animationPreset",void 0);class d extends c{constructor(){super(...arguments),this.animation=new f,this.animationPreset="mixamo"}}e([m(),a("design:type",Object)],d.prototype,"animationPreset",void 0);class v extends c{constructor(){super(...arguments),this.value="before"}applySceneParameters(e,a){return!(1!==a.size||!a.has("value"))&&(this.value=e.value,!0)}}e([m(),a("design:type",Object)],v.prototype,"value",void 0);class y extends p{constructor(){super(...arguments),this.value="before"}applySceneParameters(e,a){return!(1!==a.size||!a.has("value"))&&(this.value=e.value,!0)}}e([m(),a("design:type",Object)],y.prototype,"value",void 0);class b extends c{constructor(){super(...arguments),this.component=new y}}class P extends c{}async function g(e){return(await w(e)).actor}async function w(e){const a=x("prefab-asset",[A({id:"prefab-actor",type:"actor",actor:{type:"PrefabParamActor",params:{animationPreset:{type:u.String,value:e.prefabActorValue}},innerParams:null==e.prefabComponentValue?[]:[{path:["animation"],params:{animationPreset:{type:u.String,value:e.prefabComponentValue}}}],components:[]}})],"prefab-actor"),t=A({id:"prefab-instance",type:"prefab",assetId:a.id,prefab:{mainActorId:"prefab-actor",params:null==e.instanceParam?{}:{animationPreset:e.instanceParam},innerParams:null==e.instanceInnerParam?[]:[{path:["animation"],params:{animationPreset:e.instanceInnerParam}}]}}),{materializer:r}=h([t],new Map([[a.id,a]]));return await r.materialize(t),await r.initActorsPostInit(),{actor:r.materializedActors.get("prefab-instance/prefab-actor"),materializer:r}}function h(e,a,t=!1){const r={getObjects:()=>e,onCreate:()=>{},onUpdate:()=>{},onRemove:()=>{}},n={supportsLivePrefabParameters:t,onCreate:new s,onDelete:new s,onUpdate:new s,getAsset:o.fn(async e=>a.get(e)??null),getAssets:o.fn(async()=>Array.from(a.values()))},c={create:o.fn(async(e,a)=>{const t=new e;return null!=a&&t.position.copy(a),t}),initActor:o.fn(async e=>{e.__isInitialised=!0})};return{materializer:new l(new i,r,n,{},{renderer:{shadowMap:{needsUpdate:!1}}},[],[{name:"PrefabParamActor",type:d},{name:"LiveParamActor",type:v},{name:"SceneAttachedComponentActor",type:P}],c,[{name:"LiveParamComponent",type:y}]),assetsProvider:n}}function A(e){return{name:e.id,position:[0,0,0],rotation:[0,0,0,"XYZ"],scale:[1,1,1],...e}}function x(e,a,t){return{id:e,name:e,type:"prefab",prefab:{objects:a,mainActorId:t}}}t("prefab instance actor params",()=>{n("does not let generated prefab instance defaults override the prefab actor value",async()=>{const e=await g({prefabActorValue:"basic",instanceParam:{type:u.String,value:"mixamo"}});r(e.animationPreset).toBe("basic")}),n("applies prefab instance params when the override is explicit",async()=>{const e=await g({prefabActorValue:"basic",instanceParam:{type:u.String,value:"mixamo",override:!0}});r(e.animationPreset).toBe("mixamo")}),n("does not let generated prefab instance component defaults override prefab component values",async()=>{const e=await g({prefabActorValue:"basic",prefabComponentValue:"basic",instanceInnerParam:{type:u.String,value:"mixamo"}});r(e.animation.animationPreset).toBe("basic")}),n("applies prefab instance component params when the override is explicit",async()=>{const e=await g({prefabActorValue:"basic",prefabComponentValue:"basic",instanceInnerParam:{type:u.String,value:"mixamo",override:!0}});r(e.animation.animationPreset).toBe("mixamo")}),n("resolves direct scene actors and exposed prefab actors by scene object id",async()=>{const{actor:e,materializer:a}=await w({prefabActorValue:"basic"}),t=new d;a.materializedActors.set("direct-actor",t),r(a.resolveSceneActor("direct-actor")).toBe(t),r(a.resolveSceneActor("prefab-instance")).toBe(e)}),n("applies supported scene parameter changes without recreating the actor",async()=>{const e=A({id:"live-actor",type:"actor",actor:{type:"LiveParamActor",params:{value:{type:u.String,value:"after"}},innerParams:[],components:[]}}),a={...e.actor,params:{value:{type:u.String,value:"before"}}},{materializer:t}=h([e],new Map),n=new v,o=await t.tryApplyLiveActorParameterUpdate(n,e,JSON.stringify(a));r(o).toBe(!0),r(n.value).toBe("after")}),n("applies supported component parameter changes without recreating the actor",async()=>{const e=A({id:"live-component",type:"actor",actor:{type:"LiveComponentParamActor",params:{},innerParams:[{path:["component"],params:{value:{type:u.String,value:"after"}}}],components:[]}}),a={...e.actor,innerParams:[{path:["component"],params:{value:{type:u.String,value:"before"}}}]},{materializer:t}=h([e],new Map),n=new b,o=await t.tryApplyLiveActorParameterUpdate(n,e,JSON.stringify(a));r(o).toBe(!0),r(n.component.value).toBe("after")}),n("applies supported scene-attached component parameter changes without recreating the actor",async()=>{const e=A({id:"scene-attached-component",type:"actor",actor:{type:"SceneAttachedComponentActor",params:{},innerParams:[],components:[{type:"LiveParamComponent",params:{value:{type:u.String,value:"before"}},innerParams:[]}]}}),{materializer:a}=h([e],new Map);await a.materialize(e),await a.initActorsPostInit();const t=a.materializedActors.get(e.id),n=t.attachedComponents[0],o=JSON.stringify(e.actor);e.actor.components[0].params.value={type:u.String,value:"after"};const i=await a.tryApplyLiveActorParameterUpdate(t,e,o);r(i).toBe(!0),r(n.value).toBe("after"),r(t.attachedComponents[0]).toBe(n)}),n("applies saved prefab parameters to a runtime-spawned prefab instance",async()=>{const e=x("live-prefab",[A({id:"live-actor",type:"actor",actor:{type:"LiveParamActor",params:{value:{type:u.String,value:"before"}},components:[]}})],"live-actor"),a=structuredClone(e);a.prefab.objects[0].actor.params.value={type:u.String,value:"after"};const{materializer:t,assetsProvider:n}=h([],new Map([[e.id,e]]),!0),i=await t.createFromPrefabAsset(e,{sceneObjectChain:["runtime-instance"],runtimeSpawn:!0},void 0,void 0,!1),s=i.mainActor;n.onUpdate.next(a),await o.waitFor(()=>r(s.value).toBe("after")),r(i.mainActor).toBe(s)}),n("applies supported component changes when the actor rejects an independent change",async()=>{const e=x("partially-live-prefab",[A({id:"component-actor",type:"actor",actor:{type:"SceneAttachedComponentActor",params:{unsupported:{type:u.String,value:"before"}},components:[{type:"LiveParamComponent",params:{value:{type:u.String,value:"before"}}}]}})],"component-actor"),a=structuredClone(e);a.prefab.objects[0].actor.params.unsupported.value="after",a.prefab.objects[0].actor.components[0].params.value.value="after";const{materializer:t,assetsProvider:n}=h([],new Map([[e.id,e]]),!0),i=await t.createFromPrefabAsset(e,{sceneObjectChain:["runtime-component-instance"],runtimeSpawn:!0},void 0,void 0,!1),s=i.mainActor,c=s.attachedComponents[0],p=o.spyOn(console,"warn").mockImplementation(()=>{});n.onUpdate.next(a),await o.waitFor(()=>r(c.value).toBe("after")),r(i.mainActor).toBe(s),r(p).toHaveBeenCalledWith(r.stringContaining("were not applied")),p.mockRestore()})});/*
|
|
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{describe as e,expect as
|
|
1
|
+
import{describe as e,expect as t,it as a,vi as n}from"vitest";import{RuntimeAssetsService as s}from"../scene/runtime-asset-service.js";function o(e){return{getAssets:n.fn(async()=>e),getAsset:n.fn(async t=>e.find(e=>e.id===t)),getScenes:n.fn(),getScene:n.fn(),getSceneData:n.fn()}}function r(e){return{id:"prefab-a",name:"Prefab A",type:"prefab",prefab:{mainActorId:"actor-a",objects:[{id:"actor-a",name:"Actor A",type:"actor",position:[1,2,3],rotation:[0,0,0],scale:[1,1,1],actor:{type:"TestActor",params:{label:{type:0,value:e}},components:[{type:"TestComponent",params:{label:{type:0,value:`${e}-component`}}}]}}]}}}e("RuntimeAssetsService",()=>{a("shares concurrent asset list loads and reuses the loaded cache",async()=>{const e=[{id:"mesh-a",name:"Mesh A",type:"mesh"},{id:"material-a",name:"Material A",type:"material"}],a={getAssets:n.fn(async()=>(await new Promise(e=>setTimeout(e,5)),e)),getAsset:n.fn(),getScenes:n.fn(),getScene:n.fn(),getSceneData:n.fn()},o=new s(a);await Promise.all([o.getAssets(),o.getAssets()]),await o.getAssets(),t(a.getAssets).toHaveBeenCalledTimes(1)}),a("merges only compatible prefab parameter data into the runtime asset",async()=>{const e=r("old-value"),a=o([e]),c=new s(a,!1),i=[];c.onUpdate.subscribe(e=>i.push(e));const p=r("new-value");p.prefab.objects[0].position=[99,99,99],p.prefab.eventGraph={nodes:[{id:"ignored"}]};const l=n.spyOn(console,"warn").mockImplementation(()=>{});t(await c.applyLivePrefabParameters(p)).toBe(!0);const m=await c.getAsset(e.id);t(m.prefab.objects[0].actor.params.label.value).toBe("new-value"),t(m.prefab.objects[0].actor.components[0].params.label.value).toBe("new-value-component"),t(m.prefab.objects[0].position).toEqual([1,2,3]),t(m.prefab.eventGraph).toBeUndefined(),t(i).toEqual([m]),t(l).toHaveBeenCalledWith(t.stringContaining("event graph updates are not supported")),l.mockRestore()}),a("rejects structural prefab changes without replacing the cached asset",async()=>{const e=r("old-value"),a=o([e]),c=new s(a,!1),i=r("new-value");i.prefab.objects[0].actor.components[0].type="OtherComponent";const p=n.spyOn(console,"warn").mockImplementation(()=>{});t(await c.applyLivePrefabParameters(i)).toBe(!1),t(await c.getAsset(e.id)).toBe(e),t(p).toHaveBeenCalledWith(t.stringContaining("structure changed")),p.mockRestore()})});/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|