@hology/core 0.0.199 → 0.0.200

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/effects/vfx/vfx-asset.d.ts +17 -6
  2. package/dist/effects/vfx/vfx-materializer.js +1 -1
  3. package/dist/effects/vfx/vfx-renderers.js +1 -1
  4. package/dist/gameplay/services/physics/physics-system.js +1 -1
  5. package/dist/scene/custom-param-runtime-types.d.ts +35 -0
  6. package/dist/scene/custom-param-runtime-types.js +4 -0
  7. package/dist/scene/landscape/landscape.js +1 -1
  8. package/dist/scene/materializer.d.ts +19 -3
  9. package/dist/scene/materializer.js +1 -1
  10. package/dist/scene/model.d.ts +13 -5
  11. package/dist/scene/sky.js +1 -1
  12. package/dist/scene/storage/storage.js +1 -1
  13. package/dist/shader/graph/compiler.d.ts +80 -0
  14. package/dist/shader/graph/compiler.js +4 -0
  15. package/dist/shader/graph/index.d.ts +5 -0
  16. package/dist/shader/graph/index.js +4 -0
  17. package/dist/shader/graph/model.d.ts +79 -0
  18. package/dist/shader/graph/model.js +4 -0
  19. package/dist/shader/graph/parameters.d.ts +7 -0
  20. package/dist/shader/graph/parameters.js +4 -0
  21. package/dist/shader/graph/registry.d.ts +17 -0
  22. package/dist/shader/graph/registry.js +4 -0
  23. package/dist/shader/index.d.ts +1 -0
  24. package/dist/shader/index.js +1 -1
  25. package/dist/shader-nodes/bulge.js +1 -1
  26. package/dist/shader-nodes/depth.d.ts +2 -0
  27. package/dist/shader-nodes/depth.js +1 -1
  28. package/dist/shader-nodes/effects.d.ts +5 -0
  29. package/dist/shader-nodes/effects.js +1 -1
  30. package/dist/shader-nodes/gradient-sample.d.ts +16 -0
  31. package/dist/shader-nodes/gradient-sample.js +4 -0
  32. package/dist/shader-nodes/index.d.ts +1 -0
  33. package/dist/shader-nodes/index.js +1 -1
  34. package/dist/shader-nodes/layers.d.ts +6 -3
  35. package/dist/shader-nodes/layers.js +1 -1
  36. package/dist/shader-nodes/math.d.ts +4 -0
  37. package/dist/shader-nodes/math.js +1 -1
  38. package/dist/shader-nodes/particle.d.ts +10 -2
  39. package/dist/shader-nodes/particle.js +1 -1
  40. package/dist/shader-nodes/texture-sequence.d.ts +2 -1
  41. package/dist/shader-nodes/texture-sequence.js +1 -1
  42. package/dist/test/runtime-param-type-inference.test.d.ts +2 -0
  43. package/dist/test/runtime-param-type-inference.test.js +4 -0
  44. package/dist/test/shader-graph.test.d.ts +2 -0
  45. package/dist/test/shader-graph.test.js +4 -0
  46. package/dist/test/storage-case-collision.test.js +1 -1
  47. package/package.json +6 -2
  48. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,4 @@
1
+ import{expect as e,test as t,vi as o}from"vitest";import{DoubleSide as a,FrontSide as r,Texture as n}from"three";o.hoisted(()=>{if("undefined"==typeof HTMLCanvasElement)return;const e=new Proxy({},{get:(e,t)=>(t in e||(e[t]=("string"!=typeof t||!t.startsWith("is"))&&o.fn()),e[t]),set:(e,t,o)=>(e[t]=o,!0)});Object.defineProperty(HTMLCanvasElement.prototype,"getContext",{configurable:!0,value:()=>e}),"undefined"==typeof AudioBuffer&&Object.defineProperty(globalThis,"AudioBuffer",{configurable:!0,value:class{}})}),o.mock("three/examples/jsm/Addons.js",async e=>({...await e(),ConvexHull:class{},SkeletonUtils:{clone:e=>e},RectAreaLightHelper:class{}})),o.mock("three-shader-graph",async e=>{const t=await e();return{...t,rgb:(e,o,a)=>null==o&&null==a&&!0===e?.isColor&&"function"==typeof e.getHexString?t.rgb("#"+e.getHexString()):t.rgb(e,o,a)}}),o.mock("../rendering.js",()=>({RenderingView:class{constructor(){this._id="test",this.csm={setupMaterial:o.fn()}}getEnvTexture(e){return e}},setRenderingPaused:o.fn()}));import{materialFromAsset as d,prepareCustomParamsFromShaderGraph as s,prepareShaderGraphParameters as p}from"../scene/materializer.js";import{SerializedParamType as l}from"../scene/model.js";import{AssetsProvider as i}from"../scene/assets-provider.js";import{AssetResourceLoader as u}from"../scene/asset-resource-loader.js";import{buildShaderGraphMaterial as m,compileShaderGraph as c,compileShaderGraphPreview as v,createDefaultShaderGraphDocument as f,createDefaultVfxShaderGraphDocument as h,shaderGraphParametersToPropertyParameters as g}from"../shader/graph/index.js";import{textureSampler2d as y}from"../shader-nodes/index.js";function I(e,t,o){return{version:1,target:"surface",parameters:[],nodes:e,edges:t,outputs:o}}function b(e,t){return{id:e,name:e,type:"material",material:{type:"shaderGraph",side:r,params:{},shaderParams:{},shaderGraph:t}}}t("graph validation rejects missing nodes, invalid ports, and incompatible edges",()=>{const t=f();t.outputs.color={input:{nodeId:"missing",port:"value"}},e(()=>c(t)).toThrow(/Missing shader graph node/);const o=f();o.outputs.color={input:{nodeId:"base-color",port:"missing"}},e(()=>c(o)).toThrow(/does not have output/);const a=I([{id:"a",kind:"constant.vec2",params:{value:[1,1]}},{id:"b",kind:"constant.vec3",params:{value:[1,1,1]}},{id:"add",kind:"math.add"}],[{from:{nodeId:"a",port:"value"},to:{nodeId:"add",port:"a"}},{from:{nodeId:"b",port:"value"},to:{nodeId:"add",port:"b"}}],{color:{input:{nodeId:"add",port:"value"}}});e(()=>c(a)).toThrow(/Cannot add vec2 and vec3/)}),t("surface graph compiles to NodeShaderOutput",()=>{const t=c(f("surface"));e(t.output.color).toBeTruthy(),e(t.output.transparent).toBe(!1)}),t("sprite graph compiles with sprite-compatible material output",()=>{const t=f("sprite"),o=c(t);e(o.output.color).toBeTruthy(),e(o.output.transparent).toBe(!0)}),t("default VFX shader graphs compile mapped targets and build non-sprite materials",()=>{for(const t of["sprite","surface","decal","trail"]){const o=h(t);if(e(c(o).output.color).toBeTruthy(),"sprite"===t)continue;const a=m(o,{trailBillboard:"trail"===t});e(a.isMaterial).toBe(!0)}}),t("graph material options apply to supported material targets",()=>{const t=f("surface");t.materialOptions={side:"double",transparent:!0};const o=m(t);e(o.side).toBe(a),e(o.transparent).toBe(!0);const r=f("decal");r.materialOptions={transparent:!0};const n=m(r);e(n.transparent).toBe(!0)}),t("standard graph compiles extended material outputs and vertex transform",()=>{const t=I([{id:"metalness",kind:"constant.float",params:{value:.8}},{id:"ao",kind:"constant.float",params:{value:.5}},{id:"sheen",kind:"constant.vec3",params:{value:[.1,.2,.3]}},{id:"offset",kind:"constant.vec3",params:{value:[0,1,0]}},{id:"translate",kind:"transform.translate"}],[{from:{nodeId:"offset",port:"value"},to:{nodeId:"translate",port:"offset"}}],{metalness:{input:{nodeId:"metalness",port:"value"}},ambientOcclusion:{input:{nodeId:"ao",port:"value"}},sheenColor:{input:{nodeId:"sheen",port:"value"}},transform:{input:{nodeId:"translate",port:"value"}}}),o=c(t);e(o.output.metalness).toBeTruthy(),e(o.output.ambientOcclusion).toBeTruthy(),e(o.output.sheenColor).toBeTruthy(),e(o.output.transform).toBeTruthy();const a=m(t);e(a.outputMetalness).toBeTruthy(),e(a.outputAmbientOcclusion).toBeTruthy(),e(a.outputTransform).toBeTruthy()}),t("built-in attribute nodes compile for fragment and transform outputs",()=>{const t=I([{id:"color",kind:"builtin.color"},{id:"normal",kind:"builtin.normal"},{id:"position",kind:"builtin.position"},{id:"worldPosition",kind:"builtin.worldPosition"},{id:"translate",kind:"transform.translate"}],[{from:{nodeId:"worldPosition",port:"value"},to:{nodeId:"translate",port:"offset"}}],{color:{input:{nodeId:"color",port:"value"}},normal:{input:{nodeId:"normal",port:"value"}},roughness:{input:{nodeId:"position",port:"x"}},transform:{input:{nodeId:"translate",port:"value"}}}),o=c(t);e(o.nodes.get("color")?.outputs.value.type).toBe("rgba"),e(o.nodes.get("normal")?.outputs.value.type).toBe("vec3"),e(o.nodes.get("position")?.outputs.value.type).toBe("vec3"),e(o.nodes.get("worldPosition")?.outputs.value.type).toBe("vec3"),e(o.output.color).toBeTruthy(),e(o.output.normal).toBeTruthy(),e(o.output.transform).toBeTruthy(),e(m(t).outputTransform).toBeTruthy()}),t("painted layer mix node compiles color layers and builds a material",()=>{const t=I([{id:"base",kind:"constant.rgba",params:{value:"#224422",alpha:1}},{id:"grass",kind:"constant.rgba",params:{value:"#55aa33",alpha:1}},{id:"stone",kind:"constant.rgba",params:{value:"#777777",alpha:1}},{id:"mix",kind:"layer.mixPainted",params:{mode:"soft",enableNoise:!0,softness:.25,noiseScale:.2,noiseAmount:.4}}],[{from:{nodeId:"base",port:"value"},to:{nodeId:"mix",port:"base"}},{from:{nodeId:"grass",port:"value"},to:{nodeId:"mix",port:"layer1"}},{from:{nodeId:"stone",port:"value"},to:{nodeId:"mix",port:"layer3"}}],{color:{input:{nodeId:"mix",port:"value"}}}),o=c(t);e(o.nodes.get("mix")?.outputs.value.type).toBe("rgba"),e(o.output.color).toBeTruthy(),e(m(t).isMaterial).toBe(!0)}),t("painted layer mix node compiles sparse float layers in hard and soft modes",()=>{for(const t of["hard","soft"]){const o=I([{id:"base",kind:"constant.float",params:{value:.8}},{id:"mud",kind:"constant.float",params:{value:1}},{id:"wet",kind:"constant.float",params:{value:.25}},{id:"mix",kind:"layer.mixPainted",params:{mode:t,enableNoise:!1,softness:.3,noiseScale:.1,noiseAmount:.5}}],[{from:{nodeId:"base",port:"value"},to:{nodeId:"mix",port:"base"}},{from:{nodeId:"mud",port:"value"},to:{nodeId:"mix",port:"layer2"}},{from:{nodeId:"wet",port:"value"},to:{nodeId:"mix",port:"layer8"}}],{roughness:{input:{nodeId:"mix",port:"value"}}}),a=c(o);e(a.nodes.get("mix")?.outputs.value.type).toBe("float"),e(a.output.roughness).toBeTruthy()}}),t("painted layer mix node rejects incompatible layer types",()=>{const t=I([{id:"base",kind:"constant.vec2",params:{value:[0,1]}},{id:"layer",kind:"constant.vec3",params:{value:[1,0,0]}},{id:"mix",kind:"layer.mixPainted"}],[{from:{nodeId:"base",port:"value"},to:{nodeId:"mix",port:"base"}},{from:{nodeId:"layer",port:"value"},to:{nodeId:"mix",port:"layer1"}}],{color:{input:{nodeId:"mix",port:"value"}}});e(()=>c(t)).toThrow(/Cannot mix vec2 and vec3/)}),t("additional math, uv, shape, noise, and effect nodes compile",()=>{const t=I([{id:"uv",kind:"builtin.uv"},{id:"angle",kind:"constant.float",params:{value:.5}},{id:"scale",kind:"constant.float",params:{value:4}},{id:"half",kind:"constant.float",params:{value:.5}},{id:"axis",kind:"constant.vec3",params:{value:[0,1,0]}},{id:"rotatedUv",kind:"uv.rotate"},{id:"twirl",kind:"uv.twirl"},{id:"bulge",kind:"uv.bulge"},{id:"radial",kind:"uv.radial"},{id:"flipbook",kind:"uv.flipbook"},{id:"shape",kind:"shape.roundedRectangle"},{id:"noise",kind:"noise.simplex"},{id:"voronoi",kind:"noise.voronoi2d"},{id:"fresnel",kind:"effect.fresnel"},{id:"sin",kind:"math.sin"},{id:"pow",kind:"math.pow"},{id:"mix",kind:"math.mix"},{id:"rotateAxis",kind:"transform.rotateAxis"}],[{from:{nodeId:"uv",port:"value"},to:{nodeId:"rotatedUv",port:"uv"}},{from:{nodeId:"angle",port:"value"},to:{nodeId:"rotatedUv",port:"angle"}},{from:{nodeId:"rotatedUv",port:"value"},to:{nodeId:"twirl",port:"uv"}},{from:{nodeId:"scale",port:"value"},to:{nodeId:"twirl",port:"strength"}},{from:{nodeId:"twirl",port:"value"},to:{nodeId:"bulge",port:"uv"}},{from:{nodeId:"half",port:"value"},to:{nodeId:"bulge",port:"power"}},{from:{nodeId:"bulge",port:"value"},to:{nodeId:"radial",port:"uv"}},{from:{nodeId:"twirl",port:"value"},to:{nodeId:"shape",port:"uv"}},{from:{nodeId:"half",port:"value"},to:{nodeId:"shape",port:"width"}},{from:{nodeId:"half",port:"value"},to:{nodeId:"shape",port:"height"}},{from:{nodeId:"half",port:"value"},to:{nodeId:"shape",port:"radius"}},{from:{nodeId:"twirl",port:"value"},to:{nodeId:"noise",port:"uv"}},{from:{nodeId:"scale",port:"value"},to:{nodeId:"noise",port:"scale"}},{from:{nodeId:"twirl",port:"value"},to:{nodeId:"voronoi",port:"uv"}},{from:{nodeId:"scale",port:"value"},to:{nodeId:"voronoi",port:"scale"}},{from:{nodeId:"scale",port:"value"},to:{nodeId:"fresnel",port:"power"}},{from:{nodeId:"radial",port:"angle"},to:{nodeId:"sin",port:"value"}},{from:{nodeId:"noise",port:"value"},to:{nodeId:"pow",port:"a"}},{from:{nodeId:"half",port:"value"},to:{nodeId:"pow",port:"b"}},{from:{nodeId:"shape",port:"value"},to:{nodeId:"mix",port:"a"}},{from:{nodeId:"voronoi",port:"value"},to:{nodeId:"mix",port:"b"}},{from:{nodeId:"fresnel",port:"value"},to:{nodeId:"mix",port:"t"}},{from:{nodeId:"axis",port:"value"},to:{nodeId:"rotateAxis",port:"axis"}},{from:{nodeId:"angle",port:"value"},to:{nodeId:"rotateAxis",port:"angle"}}],{color:{input:{nodeId:"mix",port:"value"}},opacity:{input:{nodeId:"sin",port:"value"}},transform:{input:{nodeId:"rotateAxis",port:"value"}}}),o=c(t);e(o.nodes.get("mix")?.outputs.value.type).toBe("float"),e(o.nodes.get("twirl")?.outputs.value.type).toBe("vec2"),e(o.nodes.get("bulge")?.outputs.value.type).toBe("vec2"),e(o.nodes.get("radial")?.outputs.coords.type).toBe("vec2"),e(o.nodes.get("flipbook")?.outputs.value.type).toBe("vec2"),e(o.nodes.get("rotateAxis")?.outputs.value.type).toBe("mat4"),e(o.output.color).toBeTruthy(),e(o.output.opacity).toBeTruthy(),e(o.output.transform).toBeTruthy()}),t("slider input node outputs a clamped float value",()=>{const t=I([{id:"slider",kind:"input.slider",params:{value:1.25}}],[],{roughness:{input:{nodeId:"slider",port:"value"}}}),o=c(t);e(o.nodes.get("slider")?.outputs.value.type).toBe("float"),e(o.output.roughness).toBeTruthy()}),t("comparison and boolean graph nodes compile to boolean outputs",()=>{const t=I([{id:"a",kind:"constant.float",params:{value:.75}},{id:"b",kind:"constant.float",params:{value:.5}},{id:"greater",kind:"compare.greaterThan"},{id:"lessEqual",kind:"compare.lessThanOrEqual"},{id:"not",kind:"boolean.not"},{id:"and",kind:"boolean.and"},{id:"or",kind:"boolean.or"}],[{from:{nodeId:"a",port:"value"},to:{nodeId:"greater",port:"a"}},{from:{nodeId:"b",port:"value"},to:{nodeId:"greater",port:"b"}},{from:{nodeId:"a",port:"value"},to:{nodeId:"lessEqual",port:"a"}},{from:{nodeId:"b",port:"value"},to:{nodeId:"lessEqual",port:"b"}},{from:{nodeId:"lessEqual",port:"value"},to:{nodeId:"not",port:"value"}},{from:{nodeId:"greater",port:"value"},to:{nodeId:"and",port:"a"}},{from:{nodeId:"not",port:"value"},to:{nodeId:"and",port:"b"}},{from:{nodeId:"and",port:"value"},to:{nodeId:"or",port:"a"}},{from:{nodeId:"lessEqual",port:"value"},to:{nodeId:"or",port:"b"}}],{discard:{input:{nodeId:"or",port:"value"}}}),o=c(t);e(o.nodes.get("greater")?.outputs.value.type).toBe("boolean"),e(o.nodes.get("lessEqual")?.outputs.value.type).toBe("boolean"),e(o.nodes.get("not")?.outputs.value.type).toBe("boolean"),e(o.nodes.get("and")?.outputs.value.type).toBe("boolean"),e(o.nodes.get("or")?.outputs.value.type).toBe("boolean"),e(o.output.discard).toBeTruthy()}),t("split component node exposes vector and color channels as separate outputs",()=>{const t=I([{id:"vec",kind:"constant.vec3",params:{value:[.2,.4,.6]}},{id:"color",kind:"constant.rgba",params:{value:"#336699",alpha:.75}},{id:"splitVec",kind:"decompose.split"},{id:"splitColor",kind:"decompose.split"},{id:"sum",kind:"math.add"}],[{from:{nodeId:"vec",port:"value"},to:{nodeId:"splitVec",port:"value"}},{from:{nodeId:"color",port:"value"},to:{nodeId:"splitColor",port:"value"}},{from:{nodeId:"splitVec",port:"z"},to:{nodeId:"sum",port:"a"}},{from:{nodeId:"splitColor",port:"a"},to:{nodeId:"sum",port:"b"}}],{roughness:{input:{nodeId:"sum",port:"value"}}}),o=c(t);e(Object.keys(o.nodes.get("splitVec")?.outputs??{})).toEqual(["x","y","z"]),e(Object.keys(o.nodes.get("splitColor")?.outputs??{})).toEqual(["r","g","b","a","x","y","z","w"]),e(o.nodes.get("splitVec")?.outputs.z.type).toBe("float"),e(o.nodes.get("splitColor")?.outputs.a.type).toBe("float"),e(o.output.roughness).toBeTruthy()}),t("color gradient node compiles editable stops to a sampled color",()=>{const t=I([{id:"threshold",kind:"constant.float",params:{value:.75}},{id:"gradient",kind:"color.gradient",params:{stops:[{position:0,color:"#000000",alpha:1},{position:.5,color:"#ff0000",alpha:1},{position:1,color:"#ffffff",alpha:1}]}}],[{from:{nodeId:"threshold",port:"value"},to:{nodeId:"gradient",port:"t"}}],{color:{input:{nodeId:"gradient",port:"value"}}}),o=c(t);e(o.nodes.get("gradient")?.outputs.value.type).toBe("rgba"),e(o.output.color).toBeTruthy(),e(v(t,"gradient").color).toBeTruthy()}),t("graph parameters convert to property params and custom defaults",()=>{const t=f();t.parameters.push({name:"opacity",type:"float",defaultValue:.5});const o=g(t);e(o.map(e=>e.name)).toEqual(["baseColor","opacity"]),e(o.every(e=>!0===e.options.optional)).toBe(!0);const a=s(t);e(a.baseColor).toMatchObject({type:l.RgbNode,value:"#ffffff",override:!1}),e(a.opacity).toMatchObject({type:l.FloatNode,value:.5,override:!1})}),t("existing shader graph param values keep overriding unless explicitly disabled",()=>{const t=f(),o=s(t,{baseColor:{type:l.RgbNode,value:"#ff0000"}});e(o.baseColor).toMatchObject({type:l.RgbNode,value:"#ff0000",override:!0});const a=s(t,{baseColor:{type:l.RgbNode,value:"#00ff00",override:!1}});e(a.baseColor).toMatchObject({type:l.RgbNode,value:"#ffffff",override:!1})}),t("texture graph parameter defaults serialize as sampler parameters",()=>{const t=I([],[],{});t.parameters.push({name:"map",type:"texture",defaultValue:"texture-asset-id"});const o=s(t);e(o.map).toMatchObject({type:l.Sampler2DNode,value:"texture-asset-id"})}),t("shader graph params keep graph-declared serialized types over previous string params",()=>{const t=f();t.parameters.push({name:"map",type:"texture",defaultValue:null});const o=s(t,{baseColor:{type:l.String,value:"#ff0000"},map:{type:l.String,value:"texture-asset-id"}});e(o.baseColor).toMatchObject({type:l.RgbNode,value:"#ff0000"}),e(o.map).toMatchObject({type:l.Sampler2DNode,value:"texture-asset-id"})}),t("shader graph texture params resolve asset ids before compile",async()=>{const t=I([{id:"texture",kind:"input.parameter",params:{parameter:"map"}}],[],{color:{input:{nodeId:"texture",port:"value"}}});t.parameters.push({name:"map",type:"texture",defaultValue:"texture-asset-id"});const o=await p({},t,new x([{id:"texture-asset-id",name:"Map",type:"texture",fileKey:"map.png",fileFormat:"png"}]),new k);e(o.map).toBeTruthy(),e(typeof o.map).not.toBe("string"),e(c(t,{parameters:o}).output.color).toBeTruthy()}),t("material graph asset reference and local embedded graph both build materials",async()=>{const t={id:"graph-asset",name:"Reusable Graph",type:"shaderGraph",shaderGraph:f()},o=b("referenced",{source:"asset",assetId:t.id}),a=b("local",{source:"local",graph:f()}),r=new x([t,o,a]),n=new u;e((await d(o,null,r,n,[],!1)).isMaterial).toBe(!0),e((await d(a,null,r,n,[],!1)).isMaterial).toBe(!0)}),t("selected-node preview compiles scalar, vector, color, rgba, and boolean outputs",()=>{const t=[{id:"float",kind:"constant.float",params:{value:.25}},{id:"slider",kind:"input.slider",params:{value:.5}},{id:"vec2",kind:"constant.vec2",params:{value:[1,0]}},{id:"rgb",kind:"constant.vec3",params:{value:[1,.5,0]}},{id:"rgba",kind:"constant.rgba",params:{value:"#ff8800",alpha:.75}},{id:"boolean",kind:"constant.boolean",params:{value:!0}}];for(const o of t){const t=I([o],[],{color:{input:{nodeId:o.id,port:"value"}}});e(v(t,o.id).color).toBeTruthy()}}),t("texture parameter nodes expose sampled value and channel outputs",()=>{const t=I([{id:"texture",kind:"input.parameter",params:{parameter:"albedo"}}],[],{color:{input:{nodeId:"texture",port:"value"}}});t.parameters.push({name:"albedo",type:"texture",defaultValue:null});const o=c(t,{parameters:{albedo:new n}}),a=o.nodes.get("texture")?.outputs??{};e(Object.keys(a)).toEqual(["value","r","g","b","a","sampler"]),e(a.value.type).toBe("rgba"),e(a.r.type).toBe("float"),e(a.g.type).toBe("float"),e(a.b.type).toBe("float"),e(a.a.type).toBe("float"),e(a.sampler.type).toBe("sampler2d"),e(o.output.color).toBeTruthy()}),t("texture parameter nodes accept resolved sampler values",()=>{const t=I([{id:"texture",kind:"input.parameter",params:{parameter:"map"}}],[],{color:{input:{nodeId:"texture",port:"value"}}});t.parameters.push({name:"map",type:"texture",defaultValue:"texture-asset-id"});const o=c(t,{parameters:{map:y(new n)}});e(o.output.color).toBeTruthy()}),t("scene depth graph nodes expose sampled and fragment linear eye depth",()=>{const t=I([{id:"uv",kind:"builtin.screenUv"},{id:"sceneDepth",kind:"scene.sampleDepth"},{id:"fragmentDepth",kind:"scene.fragmentDepth"},{id:"depthFade",kind:"math.subtract"}],[{from:{nodeId:"uv",port:"value"},to:{nodeId:"sceneDepth",port:"uv"}},{from:{nodeId:"sceneDepth",port:"linearEyeDepth"},to:{nodeId:"depthFade",port:"a"}},{from:{nodeId:"fragmentDepth",port:"linearEyeDepth"},to:{nodeId:"depthFade",port:"b"}}],{opacity:{input:{nodeId:"depthFade",port:"value"}}}),o=c(t);e(o.nodes.get("sceneDepth")?.outputs.depth.type).toBe("float"),e(o.nodes.get("sceneDepth")?.outputs.linearEyeDepth.type).toBe("float"),e(o.nodes.get("fragmentDepth")?.outputs.linearEyeDepth.type).toBe("float"),e(o.output.opacity).toBeTruthy()});class x extends i{constructor(e){super(),this.onCreate=null,this.onDelete=null,this.onUpdate=null,this.assets=new Map(e.map(e=>[e.id,e]))}async getAsset(e){return this.assets.get(e)}async getAssets(){return Array.from(this.assets.values())}}class k extends u{async getTexture(){return new n}async getTextureArray(){return{texture:null,layerIndex:null}}}/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -1,4 +1,4 @@
1
- import{afterEach as e,beforeEach as t,describe as a,expect as r,it as o,vi as i}from"vitest";import{createRequire as s}from"node:module";import*as n from"node:fs/promises";import*as c from"node:os";import*as d from"node:path";const w=s(import.meta.url);let l,f,m;async function p(){const{ObjectStorage:e}=await import("../scene/storage/storage.js"),t=new e("asset");return t.setBasePath("data"),t}a("ObjectStorage case-insensitive file collisions",()=>{t(async()=>{i.resetModules(),f=window.require,m=window.process,l=await n.mkdtemp(d.join(c.tmpdir(),"hology-storage-")),await n.writeFile(d.join(l,"vite.config.ts"),"hologyBuild()"),Object.defineProperty(window,"require",{configurable:!0,value:e=>"chokidar"===e?{watch:()=>({on:()=>{},close:()=>{}})}:w(e)}),Object.defineProperty(window,"process",{configurable:!0,value:{argv:[`--path=${l}`]}})}),e(async()=>{await n.rm(l,{recursive:!0,force:!0}),Object.defineProperty(window,"require",{configurable:!0,value:f}),Object.defineProperty(window,"process",{configurable:!0,value:m})}),o("rejects create names that only differ by case",async()=>{const e=await p();await e.create({name:"dirt"}),await r(e.create({name:"Dirt"})).rejects.toThrow(/differs beyond letter casing/),await r(e.getAll()).resolves.toHaveLength(1)}),o("rejects prepared saves that only differ by case",async()=>{const e=await p();await e.create({name:"dirt"});const t=e.prepareCreate({name:"Dirt"});await r(e.save(t)).rejects.toThrow(/differs beyond letter casing/),await r(e.getAll()).resolves.toHaveLength(1)}),o("rejects renames that only differ by case from another object",async()=>{const e=await p();await e.create({name:"dirt"});const t=await e.create({name:"sand"});await r(e.rename(t,"Dirt")).rejects.toThrow(/differs beyond letter casing/),await r(e.get(t.id)).resolves.toMatchObject({name:"sand"})})});/*
1
+ import{afterEach as e,beforeEach as t,describe as a,expect as r,it as o,vi as s}from"vitest";import{createRequire as i}from"node:module";import*as n from"node:fs/promises";import*as c from"node:os";import*as w from"node:path";import{firstValueFrom as d}from"rxjs";const l=i(import.meta.url);let f,m,p;async function g(){const{ObjectStorage:e}=await import("../scene/storage/storage.js"),t=new e("asset");return t.setBasePath("data"),t}a("ObjectStorage case-insensitive file collisions",()=>{t(async()=>{s.resetModules(),m=window.require,p=window.process,f=await n.mkdtemp(w.join(c.tmpdir(),"hology-storage-")),await n.writeFile(w.join(f,"vite.config.ts"),"hologyBuild()"),Object.defineProperty(window,"require",{configurable:!0,value:e=>"chokidar"===e?{watch:()=>({on:()=>{},close:()=>{}})}:l(e)}),Object.defineProperty(window,"process",{configurable:!0,value:{argv:[`--path=${f}`]}})}),e(async()=>{await n.rm(f,{recursive:!0,force:!0}),Object.defineProperty(window,"require",{configurable:!0,value:m}),Object.defineProperty(window,"process",{configurable:!0,value:p})}),o("rejects create names that only differ by case",async()=>{const e=await g();await e.create({name:"dirt"}),await r(e.create({name:"Dirt"})).rejects.toThrow(/differs beyond letter casing/),await r(e.getAll()).resolves.toHaveLength(1)}),o("rejects prepared saves that only differ by case",async()=>{const e=await g();await e.create({name:"dirt"});const t=e.prepareCreate({name:"Dirt"});await r(e.save(t)).rejects.toThrow(/differs beyond letter casing/),await r(e.getAll()).resolves.toHaveLength(1)}),o("rejects renames that only differ by case from another object",async()=>{const e=await g();await e.create({name:"dirt"});const t=await e.create({name:"sand"});await r(e.rename(t,"Dirt")).rejects.toThrow(/differs beyond letter casing/),await r(e.get(t.id)).resolves.toMatchObject({name:"sand"})}),o("waits for the base path before watching folders",async()=>{const{ObjectStorage:e}=await import("../scene/storage/storage.js"),t=new e("asset"),a=d(t.watchFolders());t.setBasePath("data"),await r(a).resolves.toEqual([])})});/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hology/core",
3
- "version": "0.0.199",
3
+ "version": "0.0.200",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -38,6 +38,7 @@
38
38
  "./csm": "./dist/csm.js",
39
39
  "./shader/shader": "./dist/shader/shader.js",
40
40
  "./shader/parameter": "./dist/shader/parameter.js",
41
+ "./shader/graph": "./dist/shader/graph/index.js",
41
42
  "./shader-nodes": "./dist/shader-nodes/index.js",
42
43
  "./gameplay": "./dist/gameplay/index.js",
43
44
  "./gameplay/actors": "./dist/gameplay/actors/index.js",
@@ -125,6 +126,9 @@
125
126
  "shader/parameter": [
126
127
  "./dist/shader/parameter.d.ts"
127
128
  ],
129
+ "shader/graph": [
130
+ "./dist/shader/graph/index.d.ts"
131
+ ],
128
132
  "shader-nodes": [
129
133
  "./dist/shader-nodes/index.d.ts"
130
134
  ],
@@ -177,7 +181,7 @@
177
181
  "recast-navigation": "0.39.0",
178
182
  "rxjs": "7.8.1",
179
183
  "three-mesh-bvh": "^0.7.5",
180
- "three-shader-graph": "^0.2.48",
184
+ "three-shader-graph": "^0.2.49",
181
185
  "three-stdlib": "2.34.0",
182
186
  "ts-key-enum": "^2.0.12",
183
187
  "typedi": "^0.10.0"