@spiffcommerce/preview 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Liam Parker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # spiff-preview
2
+
3
+ A library allowing for 3D product visualization, used in tandem with the Spiff 3D suite of e-commerce plugins.
package/dist/main.js ADDED
@@ -0,0 +1,2 @@
1
+ require("@babylonjs/core/Engines/Extensions/engine.views"),require("@babylonjs/core/Materials/Textures/Loaders/ddsTextureLoader"),require("@babylonjs/core/Materials/Textures/Loaders/envTextureLoader"),require("@babylonjs/core/Materials/Textures/Loaders/ktxTextureLoader"),require("@babylonjs/core/Misc/screenshotTools"),require("@babylonjs/core/Rendering/boundingBoxRenderer"),require("@babylonjs/loaders/glTF/2.0"),require("@babylonjs/core/Debug/debugLayer"),require("@babylonjs/core/Helpers/sceneHelpers");var e=require("@babylonjs/core/Loading/sceneLoader"),t=require("@babylonjs/core/Materials/PBR/pbrMaterial"),a=require("@babylonjs/core/Materials/Textures/mirrorTexture"),i=require("@babylonjs/core/Maths/math"),r=require("@babylonjs/core/Probes/reflectionProbe"),n=require("@babylonjs/loaders/glTF"),s=require("@babylonjs/core/Actions/actionManager"),o=require("@babylonjs/core/Actions/directActions"),c=require("@babylonjs/core/Engines/engine"),l=require("@babylonjs/core/Engines/nullEngine"),h=require("@babylonjs/core/Layers/glowLayer"),u=require("@babylonjs/core/Layers/highlightLayer"),d=require("@babylonjs/core/Materials/Textures/cubeTexture"),m=require("@babylonjs/core/Materials/Textures/dynamicTexture"),g=require("@babylonjs/core/Maths/math.color"),p=require("@babylonjs/core/Maths/math.vector"),b=require("@babylonjs/core/Meshes/Compression/dracoCompression"),f=require("@babylonjs/core/Misc/observable"),y=require("@babylonjs/core/Misc/tools"),v=require("@babylonjs/core/scene"),x=require("@babylonjs/core/Materials/Textures/texture"),w=require("@babylonjs/core/Animations/animation"),M=require("@babylonjs/core/Animations/easing"),T=require("@babylonjs/core/Cameras/arcRotateCamera"),C=require("@babylonjs/core/Misc/assetsManager"),L=require("@babylonjs/core/XR/features/WebXRHitTest"),A=require("@babylonjs/core/XR/webXRTypes");function R(e,t){return Object.keys(t).forEach((function(a){"default"===a||"__esModule"===a||e.hasOwnProperty(a)||Object.defineProperty(e,a,{enumerable:!0,get:function(){return t[a]}})})),e}function P(e,t,a,i){Object.defineProperty(e,t,{get:a,set:i,enumerable:!0,configurable:!0})}var O={};P(O,"RenderingConfiguration",(()=>E)),P(O,"REFLECTION_PROBE_RESOLUTION",(()=>S));class E{static getDynamicTextureResolution(){return this.getIsMobile()||!E.offscreenRenderingSupported()?{width:1024,height:1024}:{width:2048,height:2048}}static shouldMipMap(){return!0}static offscreenRenderingSupported(){return!navigator.userAgent.includes("SamsungBrowser")&&(!!window.Worker&&!!window.OffscreenCanvas)}static getMirrorTextureResolution(){return this.getIsMobile()?512:1024}static getIsMobile(){return window.innerWidth<=480}}const S=128;n.GLTF2.GLTFLoader.RegisterExtension("glbPostProcessor",(function(e){return new I(e)})),e.SceneLoader.OnPluginActivatedObservable.add((e=>{if("gltf"===e.name){const t=e;t.useRangeRequests=!0,t.transparencyAsCoverage=!0}}));class I{constructor(e){this.name="glbPostProcessor",this.enabled=!0,this.loader=e}onReady(){this.applyReflections(this.loader.babylonScene)}loadNodeAsync(e,t,a){return this.loader.loadNodeAsync(e,t,(function(e){t.extras&&Object.keys(t.extras).forEach((a=>{const i=t.extras[a];e.metadata[a]=i})),a(e)}))}loadMaterialPropertiesAsync(e,t,a){return this.enableMaterialExtrasIfRequired(t,a),this.loader.loadMaterialPropertiesAsync(e,t,a)}dispose(){}enableMaterialExtrasIfRequired(e,a){if(e.extras&&a instanceof t.PBRMaterial){if(e.extras.sheen){const t=a;t.sheen.isEnabled=!0,t.sheen.intensity=e.extras.sheen}if(e.extras.translucency){const t=a;t.subSurface.isTranslucencyEnabled=!0,t.subSurface.translucencyIntensity=e.extras.translucency,e.extras.translucencyR&&e.extras.translucencyG&&e.extras.translucencyB&&(t.subSurface.tintColor=new(0,i.Color3)(e.extras.translucencyR,e.extras.translucencyG,e.extras.translucencyB))}if(e.extras.useDepthPrePass){const e=a;e.needDepthPrePass=!0,e.forceIrradianceInFragment=!0}if(e.extras.useParallax){const t=a;t.useParallax=!0,t.useParallaxOcclusion=!0,t.parallaxScaleBias=e.extras.useParallax}}}applyReflections(e){function t(e){const t=[];return e.transformNodes.forEach((e=>{e.metadata&&e.metadata.reflective&&t.push(...e.getChildMeshes())})),e.meshes.forEach((e=>{e.metadata&&e.metadata.reflective&&!t.includes(e)&&t.push(e)})),t}e.meshes.forEach((n=>{const s=n.metadata;s&&(s.mirrorTexture&&function(r,n=1){const s=r.material;if(!s)return;const o=new(0,a.MirrorTexture)("mirror",E.getMirrorTextureResolution(),e,!0);o.renderList=t(e);const c=r.getVerticesData("normal");if(!c)throw new Error("Mirror attribute specified on: "+r.name+"But no normals exist to generate a mirror from!");r.computeWorldMatrix(!0);const l=r.getWorldMatrix(),h=i.Vector3.TransformNormal(new(0,i.Vector3)(c[0],c[1],c[2]),l).normalize(),u=i.Plane.FromPositionAndNormal(r.position,h.scale(-1));o.mirrorPlane=u,o.level=n,s.reflectionTexture=o}(n,s.mirrorTexture),s.reflectionProbe&&function(a){const i=a.material,n=new(0,r.ReflectionProbe)("probe-"+i.name,S,e);n.attachToMesh(a),n.renderList&&n.renderList.push(...t(e)),i.reflectionTexture=n.cubeTexture}(n))}))}}var B={};let F;var q;let N;var j;P(B,"ProductCameraRig",(()=>F)),P(B,"MaterialEffectMode",(()=>N)),(q=F||(F={}))[q.Orbit=0]="Orbit",q[q.Pan=1]="Pan",(j=N||(N={})).None="None",j.RemoveWhenSelected="RemoveWhenSelected",j.ApplyWhenSelected="ApplyWhenSelected";var D={};P(D,"SpiffCommerce3DPreviewService",(()=>ae)),P(D,"createBaseModel",(()=>ie));const k=new Map;async function _(t,a,i){return new Promise(((r,n)=>{const s=k.get(t);if(s&&s.scene.uid===a.uid)return r(s);e.SceneLoader.LoadAssetContainerAsync(t,void 0,a,i).then((e=>{k.set(t,e),r(e)})).catch(n)}))}class V{constructor(e){this.customOptions=e}get options(){return this.customOptions}get scene(){return{clearColor:this.getSceneClearColor(),transparentBackground:this.customOptions?.backgroundImage,environmentFile:this.customOptions?.environmentFile??"assets/model-viewer/default.env"}}get camera(){return{autoOrientation:this.customOptions?.disableAutomaticOrientation??!0,autoRotation:{enabled:this.customOptions?.autoRotation??!1,idleTimeMs:this.customOptions?.idleTimeBeforeRotation??5e3},limits:{min:{alpha:this.customOptions?.lowerAlphaLimitDeg?this.customOptions?.lowerAlphaLimitDeg*Math.PI/180:void 0,beta:this.customOptions?.lowerBetaLimitDeg?this.customOptions?.lowerBetaLimitDeg*Math.PI/180:void 0,radius:this.customOptions?.minZoomOverride},max:{alpha:this.customOptions?.upperAlphaLimitDeg?this.customOptions?.upperAlphaLimitDeg*Math.PI/180:void 0,beta:this.customOptions?.upperBetaLimitDeg?this.customOptions?.upperBetaLimitDeg*Math.PI/180:void 0,radius:this.customOptions?.maxZoomOverride}}}}get highlights(){return{enabled:this.customOptions?.highlightOnMaterialHover??!1,color:this.highlightColorFromConfig()}}getSceneClearColor=()=>{const e=this.customOptions?.backgroundImage?0:1;if(this.customOptions&&this.customOptions.backgroundImage)return new(0,g.Color4)(0,0,0,e).toLinearSpace();if(this.customOptions&&this.customOptions.backgroundColor){const t=g.Color3.FromHexString(this.customOptions.backgroundColor);return new(0,g.Color4)(t.r,t.g,t.b,e).toLinearSpace()}return new(0,g.Color4)(.98,.98,.98,e).toLinearSpace()};highlightColorFromConfig=()=>this.customOptions&&this.customOptions.highlightColor?this.hexToColor4(this.customOptions.highlightColor):new(0,g.Color4)(.98,.98,.98,1).toLinearSpace();hexToColor4=(e,t=1)=>{const a=g.Color3.FromHexString(e);return new(0,g.Color4)(a.r,a.g,a.b,t).toLinearSpace()}}function z(e,t,a){t.forEach((t=>{const i=t.getID(),r=t.getName(),n=E.getDynamicTextureResolution();e.materials.filter((e=>e.name===r)).forEach((s=>{const o=a.get(i);if(o)H(s,o),o.update(false);else{const o=function(e,t,a,i){const r=new(0,m.DynamicTexture)(e,{width:a,height:i},t,E.shouldMipMap(),x.Texture.TRILINEAR_SAMPLINGMODE,c.Engine.TEXTUREFORMAT_RGBA),n=r.getContext();n&&(n.fillStyle="#f5f5f5",n.fillRect(0,0,a,i),r.update());return r}(r,e,n.width,n.height);a.set(i,o),t.setStaticContext(o.getContext()),H(s,o),o.onLoadObservable.addOnce((()=>{o.update(false)}))}}))}))}function H(e,a){if(e instanceof t.PBRMaterial){const t=e,i=t.albedoTexture;i?(a.wrapU=i.wrapU,a.wrapV=i.wrapV):(a.wrapU=1,a.wrapV=1),t.albedoTexture=a}else{const t=e,i=t.diffuseTexture;i&&(a.wrapU=i.wrapU,a.wrapV=i.wrapV),t.diffuseTexture=a}}function U(e,t,a,i){const r=e.animationGroups,n=e=>e.targetedAnimations.map((e=>e.animation.framePerSecond)).reduce(((e,t)=>e+t),0)/e.targetedAnimations.length||0;void 0===i||void 0===a||i!==a?r.forEach((e=>{e.stop();const r=n(e);e.start(t,1,i*r,a*r)})):r.forEach((e=>{e.stop();const a=n(e),r=i*a;e.start(t,1,r,r)}))}function W(e){e.animationGroups.forEach((e=>{e.stop()}))}function G(e,t,a){var i,r,n;e.stopAnimation(t),t.animations=[],Math.abs(t.alpha)>2*Math.PI&&(t.alpha=(i=t.alpha,r=0,n=2*Math.PI,i<r?n-(r-i)%(n-r):r+(i-r)%(n-r)));const s=[],o=a.target,c=o?1:0;if(a.target&&s.push(X("cameraTargetLerp","target",(new(0,p.Vector3)).copyFrom(t.target),new(0,p.Vector3)(a.target.x,a.target.y,a.target.z),w.Animation.ANIMATIONTYPE_VECTOR3,0)),s.push(X("cameraAlphaLerp","alpha",t.alpha,K(a.lonDeg),w.Animation.ANIMATIONTYPE_FLOAT,c)),s.push(X("cameraBetaLerp","beta",t.beta,K(a.latDeg),w.Animation.ANIMATIONTYPE_FLOAT,c)),void 0!==a.radius){const e=Math.max(.01,a.radius);s.push(X("cameraRadiusLerp","radius",t.radius,e,w.Animation.ANIMATIONTYPE_FLOAT,c))}t.animations.push(...s);const l=t.useAutoRotationBehavior;t.disableAutoRotationBehavior(),e.beginAnimation(t,0,o?120:60,!1,1,(()=>{t.animations=[],l&&t.enableAutoRotationBehavior()}))}function K(e){return e*Math.PI/180}function X(e,t,a,i,r,n=0,s=w.Animation.ANIMATIONLOOPMODE_CONSTANT){const o=new(0,M.QuadraticEase);o.setEasingMode(M.EasingFunction.EASINGMODE_EASEINOUT);const c=new(0,w.Animation)(e,t,60,r,s),l=[];return n>0&&l.push({frame:0,value:a}),l.push({frame:60*n,value:a}),l.push({frame:60*(n+1),value:i}),c.setKeys(l),c.setEasingFunction(o),c}class Z extends T.ArcRotateCamera{constructor(e,t,a,i,r,n,s,o){super(e,t,a,i,r,n,o),this.minZ=.01,this.maxZ=1e3*this.radius,this.lowerRadiusLimit=.01*this.radius,this.enableFramingBehavior(),this.upperRadiusLimit=1.5*this.radius,this.wheelPrecision=100/this.radius,this.pinchPrecision=300/this.radius,this.wheelDeltaPercentage=.01,this.pinchDeltaPercentage=.005,this.useNaturalPinchZoom=!0,s.camera.autoOrientation&&(this.alpha+=Math.PI),s&&(s.camera.limits.min.beta&&(this.lowerBetaLimit=s.camera.limits.min.beta),s.camera.limits.max.beta&&(this.upperBetaLimit=s.camera.limits.max.beta),s.camera.limits.min.alpha&&(this.lowerAlphaLimit=s.camera.limits.min.alpha),s.camera.limits.max.alpha&&(this.upperAlphaLimit=s.camera.limits.max.alpha),s.camera.limits.min.radius&&(this.lowerRadiusLimit=s.camera.limits.min.radius),s.camera.limits.max.radius&&(this.upperRadiusLimit=s.camera.limits.max.radius),s.camera.autoRotation.enabled&&this.enableAutoRotationBehavior(s.camera.autoRotation.idleTimeMs))}lastFocus=new(0,p.Vector3)(0,0,0);getFramingBehavior(){return this.getBehaviorByName("Framing")}getAutoRotationBehavior(){const e=this.getBehaviorByName("AutoRotation");return e||void 0}enableFramingBehavior(){this.useFramingBehavior=!0;const e=this.getFramingBehavior();e.attach(this),e.framingTime=0,e.elevationReturnTime=-1,e.zoomStopsAnimation=!1,this.lowerRadiusLimit=null;const t=Y(this._scene);return e.zoomOnBoundingInfo(t.min,t.max),this.wheelPrecision=100/this.radius,null===this.lowerRadiusLimit&&(this.lowerRadiusLimit=.1),this.lastFocus.copyFrom(this.target),e}rerunFramingBehavior(e){const t=this.getFramingBehavior();t.framingTime=800;const a=Y(this._scene);t.zoomOnBoundingInfo(a.min,a.max,void 0,(()=>{e()})),t.framingTime=0}enableAutoRotationBehavior(e=5e3){this.useAutoRotationBehavior=!0;const t=this.getAutoRotationBehavior();t&&(t.idleRotationWaitTime=e)}disableAutoRotationBehavior(){this.useAutoRotationBehavior=!1}static create(e,t){e.activeCamera&&(e.activeCamera.dispose(),e.activeCamera=null);const a=Y(e),i=a.max.subtract(a.min),r=a.min.add(i.scale(.5)),n=new Z("ProductCamera",-Math.PI/2,Math.PI/2,1.5*i.length(),r,e,t);return n.panningInertia=0,n.panningOriginTarget.copyFrom(r),n.onAfterCheckInputsObservable.add((()=>{n.panningSensibility=1e3/i.length()})),e.activeCamera=n,n}}function Y(e){const t=e.meshes.filter((e=>e.name.toLowerCase().endsWith("_t")||e.name.toLowerCase().includes("_t_")));return e.getWorldExtends((e=>e.isVisible&&e.isEnabled()&&(0===t.length||t.includes(e))))}const Q={albedoTexture:"albedoMapKey",bumpTexture:"normalMapKey",ambientTexture:"ambientMapKey",emissiveTexture:"emissionMapKey",opacityTexture:"alphaMapKey",metallicTexture:"metallicMapKey",refractionTexture:"refractionMapKey"};function $(e,t,a,i){["albedoTexture","bumpTexture","ambientTexture","emissiveTexture","opacityTexture","metallicTexture","refractionTexture"].forEach((r=>{!function(e,t,a,i,r){const n=Q[e];if(!n)throw new Error("Unexpected texture name encountered.");const s=t[n];s?i.addTextureTask(e,s,!1,!1):r&&a[e]&&(a[e]&&a[e].dispose(),a[e]=null,function(e,t){"opacityTexture"===e&&(t.useAlphaFromAlbedoTexture=!0);"metallicTexture"===e&&(t.useRoughnessFromMetallicTextureAlpha=!1,t.useRoughnessFromMetallicTextureGreen=!1,t.useMetallnessFromMetallicTextureBlue=!1);"refractionTexture"===e&&(t.subSurface.isRefractionEnabled=!1,t.subSurface.refractionIntensity=1)}(e,a))}(r,e,t,a,i)})),function(e,t){if(!e.clearCoat)return;e.clearCoat===N.RemoveWhenSelected?(t.clearCoat.isEnabled=!1,t.clearCoat.indexOfRefraction=1.5):e.clearCoat===N.ApplyWhenSelected&&(t.clearCoat.isEnabled=!0,t.clearCoat.indexOfRefraction=e.clearCoatIOR||t.clearCoat.indexOfRefraction)}(e,t)}function J(e,t,a,i){"opacityTexture"===e&&(t.useAlphaFromAlbedoTexture=!1),"metallicTexture"===e&&(t.useRoughnessFromMetallicTextureAlpha=!1,t.useRoughnessFromMetallicTextureGreen=!0,t.useMetallnessFromMetallicTextureBlue=!0),"refractionTexture"===e&&(t.subSurface.isRefractionEnabled=!0,t.subSurface.refractionIntensity=a.refractionIntensity||1),t[e]=i}class ee{materialVariantMap=new Map;keysThatRemovedBaseModel=[];loadedContainerForKey=new Map;async applyMaterial(e,t,a,i,r){return new Promise((n=>{const s=e.materials.filter((e=>e.name===t)),o=this.materialVariantMap.get(t);if(this.materialVariantMap.set(t,{...o,...a}),0===s.length)return void n(void 0);const c=new(0,C.AssetsManager)(e);c.useDefaultLoadingScreen=!1,s.forEach((e=>$(a,e,c,r))),c.onProgress=(e,t,a)=>{i&&i(e/t*100,100,a.name)},c.onFinish=e=>{e.forEach((e=>{const t=e;i&&i(100,100,e.name),s.forEach((i=>J(e.name,i,a,t.texture)))})),n(void 0)},c.loadAsync()}))}async applyModel(e,t,a,i,r){if(i&&a&&!this.keysThatRemovedBaseModel.includes(t)&&this.keysThatRemovedBaseModel.push(t),!i){const a=this.keysThatRemovedBaseModel.includes(t);return this.loadedContainerForKey.get(t)?.removeAllFromScene(),e&&a&&await ie(e.metadata.baseModel,e),Promise.resolve()}const n=await _(i,e,r);if(this.loadedContainerForKey.has(t)&&this.loadedContainerForKey.get(t)?.removeAllFromScene(),a){(await _(e.metadata.baseModel,e)).removeAllFromScene()}n.addAllToScene(),this.loadedContainerForKey.set(t,n);const s=[];this.materialVariantMap.forEach((async(t,a)=>{s.push(this.applyMaterial(e,a,t))})),await Promise.all(s)}}var te=async(e,t)=>{const a=await t.createDefaultXRExperienceAsync({uiOptions:{sessionMode:"immersive-ar",referenceSpaceType:"local-floor",onError:e=>{console.log(e)}}}),i=a.baseExperience.featuresManager.enableFeature(L.WebXRHitTest.Name,"latest",{disablePermanentHitTest:!0,enableTransientHitTest:!0,useReferenceSpace:!0});let r=null;i.onHitTestResultObservable.add((e=>{r=e.length?e[0]:void 0})),t.onPointerDown=()=>{if(r&&a.baseExperience.state===A.WebXRState.IN_XR){const e=t.getNodeByName("__root__");r.transformationMatrix.decompose(void 0,e.rotationQuaternion,e.position)}}};class ae{loadProgress=new Map([["initialScene",0]]);materialReadyToLoadCallbacks=new Map;modelReadyToLoadCallbacks=new Map;focusLostNotified=!1;loadObservable=new(0,f.Observable);focusLostObservable=new(0,f.Observable);dynamicTextures=new Map;variantManager=new ee;constructor(e,t){this.configuration=new V(t);b.DracoCompression.Configuration={decoder:{wasmUrl:"https://www.gstatic.com/draco/versioned/decoders/1.5.3/draco_wasm_wrapper_gltf.js",wasmBinaryUrl:"https://www.gstatic.com/draco/versioned/decoders/1.5.3/draco_decoder_gltf.wasm",fallbackUrl:"https://www.gstatic.com/draco/versioned/decoders/1.5.3/draco_decoder_gltf.js"}},e&&(e.getContext("webgl2")||e.getContext("webgl"));const a=console.log;console.log=()=>{};const i=e?new(0,c.Engine)(e,!0,{premultipliedAlpha:!1,preserveDrawingBuffer:!!t?.backgroundImage,audioEngine:!1,stencil:this.configuration.highlights.enabled,forceSRGBBufferSupportState:!0}):new(0,l.NullEngine);console.log=a,i.hideLoadingUI(),window.addEventListener("resize",this.fireResizeEvent.bind(this)),this.engine=i,this.scene=new(0,v.Scene)(i)}registerFocusLostListener(e){this.focusLostObservable.add(e)}unregisterFocusLostListener(e){this.focusLostObservable.removeCallback(e)}registerLoadProgressListener(e){this.loadObservable.add(e),e(this.getLoadListenerEvent())}unregisterLoadProgressListener(e){this.loadObservable.removeCallback(e)}registerView(e){const t=e.height,a=e.width;this.engine.registerView(e),e.setAttribute("height",t.toString()),e.setAttribute("width",a.toString()),this.orbitEnabled()||this.setCameraState(F.Pan)}getNumViewports(){return this.engine.views?.length||0}unregisterView(e){this.engine.unRegisterView(e),this.engine.inputElement=null}shutdown(){this.engine&&this.engine.dispose(),window.removeEventListener("resize",this.fireResizeEvent)}getSceneInitializationProgress(){return this.loadProgress.get("initialScene")}async initialize(e,t){if(this.scene.clearColor=this.configuration.scene.clearColor,this.scene.metadata={baseModel:e},this.scene.environmentTexture=d.CubeTexture.CreateFromPrefilteredData(this.configuration.scene.environmentFile,this.scene),e){const t=99;await ie(e,this.scene,(e=>{this.loadProgress.set("initialScene",e.loaded*t/e.total),this.notifyLoadHandlers()}))}this.configuration.highlights.enabled&&this.scene.meshes.forEach((e=>{"targetcube_t"!==e.name&&"backgroundShell"!==e.name&&(e.isPickable=!0,e.actionManager||(e.actionManager=new(0,s.ActionManager)(this.scene)),e.actionManager.registerAction(new(0,o.ExecuteCodeAction)(s.ActionManager.OnPointerOutTrigger,(()=>{this.setHighlights([])}))),e.actionManager.registerAction(new(0,o.ExecuteCodeAction)(s.ActionManager.OnPointerOverTrigger,(e=>{if(e.meshUnderPointer){const t=e.meshUnderPointer.material;t&&this.setHighlights([t])}}))))}));const a=Z.create(this.scene,this.configuration),i=t?.getAll()||new Map;z(this.scene,i,this.dynamicTextures);if(this.scene.materials.some((e=>"emissiveTexture"in e&&null!==e.emissiveTexture))){new(0,h.GlowLayer)("GlowLayer",this.scene).intensity=.5}W(this.scene),this.engine.runRenderLoop((()=>{if(!this.engine.views)return;const e=this.engine.views[0],t=this.engine.inputElement;(!t||e&&t&&t.id!==e.target.id)&&this.reattachControls(e.target),i.forEach(((e,t)=>{const a=this.dynamicTextures.get(t);a&&e.getStaticContextDirty()&&a.isReady()&&(a.update(!1),e.setStaticContextDirty(!1))})),this.configuration.scene.transparentBackground&&this.engine.views.forEach((e=>{const t=this.engine.getRenderingCanvas();e.target.getContext("2d").clearRect(0,0,t.width,t.height)})),this.scene.render(),100!==this.getSceneInitializationProgress()&&(this.loadProgress.set("initialScene",100),this.materialReadyToLoadCallbacks.forEach(((e,t)=>{e.forEach(((e,a)=>{this.applyMaterialVariant(t,a,e)}))})),this.materialReadyToLoadCallbacks.clear(),this.modelReadyToLoadCallbacks.forEach((e=>{e(this.scene)})),this.modelReadyToLoadCallbacks.clear(),this.queuedModelAnimation&&(this.executeModelAnimation(this.queuedModelAnimation),this.queuedModelAnimation=void 0),this.queuedCameraAnimation&&(this.executeCameraAnimation(this.queuedCameraAnimation),this.queuedCameraAnimation=void 0),this.notifyLoadHandlers()),a.target.equalsWithEpsilon(a.lastFocus,.1)||this.focusLostNotified||(this.focusLostObservable.notifyObservers(void 0),this.focusLostNotified=!0)}))}executeModelAnimation(e){100===this.getSceneInitializationProgress()?U(this.scene,e.loop,e.to,e.from):this.queuedModelAnimation=e}executeCameraAnimation(e){100===this.getSceneInitializationProgress()&&this.scene.activeCamera?G(this.scene,this.scene.activeCamera,e):this.queuedCameraAnimation=e}getCameraPose(){if(this.scene){const e=this.scene.activeCamera;if(e)return{lonDeg:Math.round(180*e.alpha/Math.PI),latDeg:Math.round(180*e.beta/Math.PI),radius:Math.round(1e4*(e.radius+Number.EPSILON))/1e4,target:{x:e.target.x,y:e.target.y,z:e.target.z}}}}setCameraPose(e){if(this.scene){const t=this.scene.activeCamera;t&&(t.target=new(0,p.Vector3)(e.target.x,e.target.y,e.target.z),t.radius=e.radius,t.alpha=e.latDeg,t.beta=e.lonDeg)}}async applyMaterialVariant(e,t,a,i){if(100===this.getSceneInitializationProgress())await this.variantManager.applyMaterial(this.scene,e,a,((e,t,a)=>{this.loadProgress.set(`key_${a}`,e/t*100),this.notifyLoadHandlers()}),i);else if(this.materialReadyToLoadCallbacks.has(e)){this.materialReadyToLoadCallbacks.get(e)?.set(t,a)}else{this.materialReadyToLoadCallbacks.set(e,new Map);this.materialReadyToLoadCallbacks.get(e)?.set(t,a)}}async applyModelVariant(e,a,i){100===this.getSceneInitializationProgress()?(await this.variantManager.applyModel(this.scene,e,i||!1,a.model,(t=>{this.loadProgress.set(e,100*t.loaded/t.total),this.notifyLoadHandlers()})),this.scene.materials.forEach((e=>{if(e&&0===e.getBindedMeshes().length){const a=e instanceof t.PBRMaterial&&!(e.albedoTexture instanceof m.DynamicTexture);e.dispose(!1,a)}})),z(this.scene,a.contextService.getAll(),this.dynamicTextures),W(this.scene)):this.modelReadyToLoadCallbacks.set(e,(()=>{this.applyModelVariant(e,a,i)}))}setCameraState(e){if(!this.engine?.views||!this.engine?.views[0])throw new Error("No views attached, camera state requires a view to attach controls onto.");e===F.Orbit?this.reattachControls(this.engine.views[0].target,2):this.reattachControls(this.engine.views[0].target,0)}animateToLastCameraFocus(){return new Promise((e=>{const t=this.scene.activeCamera,a=this.configuration;t.rerunFramingBehavior((()=>{this.focusLostNotified=!1,a.camera.limits.min.radius&&(t.lowerRadiusLimit=a.camera.limits.min.radius),a.camera.limits.max.radius&&(t.upperRadiusLimit=a.camera.limits.max.radius),e()}))}))}setAutoRotation(e){const t=this.scene.activeCamera;this.configuration.camera.autoRotation.enabled&&t&&(e?t.enableAutoRotationBehavior(this.configuration.camera.autoRotation.idleTimeMs):t.disableAutoRotationBehavior())}getCurrentConfiguration(){return this.configuration.options}async renderSceneScreenshot(e,t){const a=this.scene.activeCamera;if(!a)throw new Error("Missing product camera, cannot render screenshot!");var i;(i=a).getScene().stopAnimation(i),i.animations=[];const r=a.alpha,n=a.beta,s=a.radius,o=t.latDeg*Math.PI/180,c=t.lonDeg*Math.PI/180;a.alpha=c,a.beta=o,a.radius=t.radius||a.radius;const l=await y.Tools.CreateScreenshotUsingRenderTargetAsync(this.engine,a,e,"image/png",2,!0);return a.alpha=r,a.beta=n,a.radius=s,l}orbitEnabled(){const e=this.configuration;if(!e)return!0;const t=e.camera.limits.min.alpha,a=e.camera.limits.max.alpha,i=e.camera.limits.min.beta,r=e.camera.limits.max.beta;if(void 0===t||void 0===a||void 0===i||void 0===r)return!0;const n=[i,r],s=[t,a].every((e=>e===t)),o=n.every((e=>e===i));return!s&&!o}fireResizeEvent(){this.getNumViewports()>0&&this.engine.resize()}onMaterialSelected(e){this.scene.meshes.forEach((t=>{"targetcube_t"!==t.name&&"backgroundShell"!==t.name&&(t.actionManager||(t.actionManager=new(0,s.ActionManager)(this.scene)),t.actionManager.registerAction(new(0,o.ExecuteCodeAction)(s.ActionManager.OnPickDownTrigger,(t=>{if(t.meshUnderPointer){const a=t.meshUnderPointer.material;a&&e({id:a.id,name:a.name})}}))))}))}listMaterials(){const e=this.scene?.materials;return e?e.map((e=>({id:e.id,name:e.name}))):[]}setHighlights(e,t){0===e.length&&(this.highlightLayer?.dispose(),this.highlightLayer=void 0),this.highlightLayer||(this.highlightLayer=new(0,u.HighlightLayer)("highlights",this.scene,{isStroke:!0,blurVerticalSize:.85,blurHorizontalSize:.85}),this.highlightLayer.innerGlow=!0,this.highlightLayer.outerGlow=!1),this.highlightLayer.removeAllMeshes();const a=t?new(0,g.Color3)(t[0],t[1],t[2]).toLinearSpace():void 0;e.forEach((e=>{const t=this.scene.materials.find((t=>t.name===e.name&&t.id===e.id));t&&t.getBindedMeshes().forEach((e=>this.highlightLayer?.addMesh(e,a||g.Color3.FromHexString("#fcba03"))))}))}initXRExperience(e){te(0,this.scene)}reattachControls(e,t=2){this.scene.detachControl(),this.engine.inputElement=e;const a=this.scene.activeCamera;if(a){a.attachControl(!0,!1,t);a.inputs.attached.pointers.multiTouchPanning=!1}this.scene.attachControl(!0,!0,!0)}getLoadListenerEvent(){const e=Array.from(this.loadProgress.values()).filter((e=>e<100)),t=e.reduce(((e,t)=>e+t),0)/e.length||0;return{loadValue:0===e.length?100:t,sceneInitialized:100===this.getSceneInitializationProgress()}}notifyLoadHandlers(){this.loadObservable.notifyObservers(this.getLoadListenerEvent())}}async function ie(e,t,a){(await _(e,t,a)).addAllToScene()}R(module.exports,B),R(module.exports,D),R(module.exports,O);
2
+ //# sourceMappingURL=main.js.map
package/dist/module.js ADDED
@@ -0,0 +1,2 @@
1
+ import"@babylonjs/core/Engines/Extensions/engine.views";import"@babylonjs/core/Materials/Textures/Loaders/ddsTextureLoader";import"@babylonjs/core/Materials/Textures/Loaders/envTextureLoader";import"@babylonjs/core/Materials/Textures/Loaders/ktxTextureLoader";import"@babylonjs/core/Misc/screenshotTools";import"@babylonjs/core/Rendering/boundingBoxRenderer";import"@babylonjs/loaders/glTF/2.0";import"@babylonjs/core/Debug/debugLayer";import"@babylonjs/core/Helpers/sceneHelpers";import{SceneLoader as e}from"@babylonjs/core/Loading/sceneLoader";import{PBRMaterial as t}from"@babylonjs/core/Materials/PBR/pbrMaterial";import{MirrorTexture as a}from"@babylonjs/core/Materials/Textures/mirrorTexture";import{Color3 as i,Vector3 as r,Plane as s}from"@babylonjs/core/Maths/math";import{ReflectionProbe as o}from"@babylonjs/core/Probes/reflectionProbe";import{GLTF2 as n}from"@babylonjs/loaders/glTF";import{ActionManager as c}from"@babylonjs/core/Actions/actionManager";import{ExecuteCodeAction as l}from"@babylonjs/core/Actions/directActions";import{Engine as h}from"@babylonjs/core/Engines/engine";import{NullEngine as m}from"@babylonjs/core/Engines/nullEngine";import{GlowLayer as u}from"@babylonjs/core/Layers/glowLayer";import{HighlightLayer as d}from"@babylonjs/core/Layers/highlightLayer";import{CubeTexture as g}from"@babylonjs/core/Materials/Textures/cubeTexture";import{DynamicTexture as p}from"@babylonjs/core/Materials/Textures/dynamicTexture";import{Color3 as f,Color4 as b}from"@babylonjs/core/Maths/math.color";import{Vector3 as y}from"@babylonjs/core/Maths/math.vector";import{DracoCompression as v}from"@babylonjs/core/Meshes/Compression/dracoCompression";import{Observable as w}from"@babylonjs/core/Misc/observable";import{Tools as x}from"@babylonjs/core/Misc/tools";import{Scene as M}from"@babylonjs/core/scene";import{Texture as T}from"@babylonjs/core/Materials/Textures/texture";import{Animation as R}from"@babylonjs/core/Animations/animation";import{QuadraticEase as L,EasingFunction as C}from"@babylonjs/core/Animations/easing";import{ArcRotateCamera as A}from"@babylonjs/core/Cameras/arcRotateCamera";import{AssetsManager as P}from"@babylonjs/core/Misc/assetsManager";import{WebXRHitTest as E}from"@babylonjs/core/XR/features/WebXRHitTest";import{WebXRState as O}from"@babylonjs/core/XR/webXRTypes";function S(e,t,a,i){Object.defineProperty(e,t,{get:a,set:i,enumerable:!0,configurable:!0})}var I={};S(I,"RenderingConfiguration",(()=>B)),S(I,"REFLECTION_PROBE_RESOLUTION",(()=>F));class B{static getDynamicTextureResolution(){return this.getIsMobile()||!B.offscreenRenderingSupported()?{width:1024,height:1024}:{width:2048,height:2048}}static shouldMipMap(){return!0}static offscreenRenderingSupported(){return!navigator.userAgent.includes("SamsungBrowser")&&(!!window.Worker&&!!window.OffscreenCanvas)}static getMirrorTextureResolution(){return this.getIsMobile()?512:1024}static getIsMobile(){return window.innerWidth<=480}}const F=128;n.GLTFLoader.RegisterExtension("glbPostProcessor",(function(e){return new N(e)})),e.OnPluginActivatedObservable.add((e=>{if("gltf"===e.name){const t=e;t.useRangeRequests=!0,t.transparencyAsCoverage=!0}}));class N{constructor(e){this.name="glbPostProcessor",this.enabled=!0,this.loader=e}onReady(){this.applyReflections(this.loader.babylonScene)}loadNodeAsync(e,t,a){return this.loader.loadNodeAsync(e,t,(function(e){t.extras&&Object.keys(t.extras).forEach((a=>{const i=t.extras[a];e.metadata[a]=i})),a(e)}))}loadMaterialPropertiesAsync(e,t,a){return this.enableMaterialExtrasIfRequired(t,a),this.loader.loadMaterialPropertiesAsync(e,t,a)}dispose(){}enableMaterialExtrasIfRequired(e,a){if(e.extras&&a instanceof t){if(e.extras.sheen){const t=a;t.sheen.isEnabled=!0,t.sheen.intensity=e.extras.sheen}if(e.extras.translucency){const t=a;t.subSurface.isTranslucencyEnabled=!0,t.subSurface.translucencyIntensity=e.extras.translucency,e.extras.translucencyR&&e.extras.translucencyG&&e.extras.translucencyB&&(t.subSurface.tintColor=new i(e.extras.translucencyR,e.extras.translucencyG,e.extras.translucencyB))}if(e.extras.useDepthPrePass){const e=a;e.needDepthPrePass=!0,e.forceIrradianceInFragment=!0}if(e.extras.useParallax){const t=a;t.useParallax=!0,t.useParallaxOcclusion=!0,t.parallaxScaleBias=e.extras.useParallax}}}applyReflections(e){function t(e){const t=[];return e.transformNodes.forEach((e=>{e.metadata&&e.metadata.reflective&&t.push(...e.getChildMeshes())})),e.meshes.forEach((e=>{e.metadata&&e.metadata.reflective&&!t.includes(e)&&t.push(e)})),t}e.meshes.forEach((i=>{const n=i.metadata;n&&(n.mirrorTexture&&function(i,o=1){const n=i.material;if(!n)return;const c=new a("mirror",B.getMirrorTextureResolution(),e,!0);c.renderList=t(e);const l=i.getVerticesData("normal");if(!l)throw new Error("Mirror attribute specified on: "+i.name+"But no normals exist to generate a mirror from!");i.computeWorldMatrix(!0);const h=i.getWorldMatrix(),m=r.TransformNormal(new r(l[0],l[1],l[2]),h).normalize(),u=s.FromPositionAndNormal(i.position,m.scale(-1));c.mirrorPlane=u,c.level=o,n.reflectionTexture=c}(i,n.mirrorTexture),n.reflectionProbe&&function(a){const i=a.material,r=new o("probe-"+i.name,F,e);r.attachToMesh(a),r.renderList&&r.renderList.push(...t(e)),i.reflectionTexture=r.cubeTexture}(i))}))}}var j={};let D;var k;let _;var z;S(j,"ProductCameraRig",(()=>D)),S(j,"MaterialEffectMode",(()=>_)),(k=D||(D={}))[k.Orbit=0]="Orbit",k[k.Pan=1]="Pan",(z=_||(_={})).None="None",z.RemoveWhenSelected="RemoveWhenSelected",z.ApplyWhenSelected="ApplyWhenSelected";var V={};S(V,"SpiffCommerce3DPreviewService",(()=>se)),S(V,"createBaseModel",(()=>oe));const H=new Map;async function U(t,a,i){return new Promise(((r,s)=>{const o=H.get(t);if(o&&o.scene.uid===a.uid)return r(o);e.LoadAssetContainerAsync(t,void 0,a,i).then((e=>{H.set(t,e),r(e)})).catch(s)}))}class W{constructor(e){this.customOptions=e}get options(){return this.customOptions}get scene(){return{clearColor:this.getSceneClearColor(),transparentBackground:this.customOptions?.backgroundImage,environmentFile:this.customOptions?.environmentFile??"assets/model-viewer/default.env"}}get camera(){return{autoOrientation:this.customOptions?.disableAutomaticOrientation??!0,autoRotation:{enabled:this.customOptions?.autoRotation??!1,idleTimeMs:this.customOptions?.idleTimeBeforeRotation??5e3},limits:{min:{alpha:this.customOptions?.lowerAlphaLimitDeg?this.customOptions?.lowerAlphaLimitDeg*Math.PI/180:void 0,beta:this.customOptions?.lowerBetaLimitDeg?this.customOptions?.lowerBetaLimitDeg*Math.PI/180:void 0,radius:this.customOptions?.minZoomOverride},max:{alpha:this.customOptions?.upperAlphaLimitDeg?this.customOptions?.upperAlphaLimitDeg*Math.PI/180:void 0,beta:this.customOptions?.upperBetaLimitDeg?this.customOptions?.upperBetaLimitDeg*Math.PI/180:void 0,radius:this.customOptions?.maxZoomOverride}}}}get highlights(){return{enabled:this.customOptions?.highlightOnMaterialHover??!1,color:this.highlightColorFromConfig()}}getSceneClearColor=()=>{const e=this.customOptions?.backgroundImage?0:1;if(this.customOptions&&this.customOptions.backgroundImage)return new b(0,0,0,e).toLinearSpace();if(this.customOptions&&this.customOptions.backgroundColor){const t=f.FromHexString(this.customOptions.backgroundColor);return new b(t.r,t.g,t.b,e).toLinearSpace()}return new b(.98,.98,.98,e).toLinearSpace()};highlightColorFromConfig=()=>this.customOptions&&this.customOptions.highlightColor?this.hexToColor4(this.customOptions.highlightColor):new b(.98,.98,.98,1).toLinearSpace();hexToColor4=(e,t=1)=>{const a=f.FromHexString(e);return new b(a.r,a.g,a.b,t).toLinearSpace()}}function G(e,t,a){t.forEach((t=>{const i=t.getID(),r=t.getName(),s=B.getDynamicTextureResolution();e.materials.filter((e=>e.name===r)).forEach((o=>{const n=a.get(i);if(n)q(o,n),n.update(false);else{const n=function(e,t,a,i){const r=new p(e,{width:a,height:i},t,B.shouldMipMap(),T.TRILINEAR_SAMPLINGMODE,h.TEXTUREFORMAT_RGBA),s=r.getContext();s&&(s.fillStyle="#f5f5f5",s.fillRect(0,0,a,i),r.update());return r}(r,e,s.width,s.height);a.set(i,n),t.setStaticContext(n.getContext()),q(o,n),n.onLoadObservable.addOnce((()=>{n.update(false)}))}}))}))}function q(e,a){if(e instanceof t){const t=e,i=t.albedoTexture;i?(a.wrapU=i.wrapU,a.wrapV=i.wrapV):(a.wrapU=1,a.wrapV=1),t.albedoTexture=a}else{const t=e,i=t.diffuseTexture;i&&(a.wrapU=i.wrapU,a.wrapV=i.wrapV),t.diffuseTexture=a}}function K(e,t,a,i){const r=e.animationGroups,s=e=>e.targetedAnimations.map((e=>e.animation.framePerSecond)).reduce(((e,t)=>e+t),0)/e.targetedAnimations.length||0;void 0===i||void 0===a||i!==a?r.forEach((e=>{e.stop();const r=s(e);e.start(t,1,i*r,a*r)})):r.forEach((e=>{e.stop();const a=s(e),r=i*a;e.start(t,1,r,r)}))}function X(e){e.animationGroups.forEach((e=>{e.stop()}))}function Z(e,t,a){var i,r,s;e.stopAnimation(t),t.animations=[],Math.abs(t.alpha)>2*Math.PI&&(t.alpha=(i=t.alpha,r=0,s=2*Math.PI,i<r?s-(r-i)%(s-r):r+(i-r)%(s-r)));const o=[],n=a.target,c=n?1:0;if(a.target&&o.push(Q("cameraTargetLerp","target",(new y).copyFrom(t.target),new y(a.target.x,a.target.y,a.target.z),R.ANIMATIONTYPE_VECTOR3,0)),o.push(Q("cameraAlphaLerp","alpha",t.alpha,Y(a.lonDeg),R.ANIMATIONTYPE_FLOAT,c)),o.push(Q("cameraBetaLerp","beta",t.beta,Y(a.latDeg),R.ANIMATIONTYPE_FLOAT,c)),void 0!==a.radius){const e=Math.max(.01,a.radius);o.push(Q("cameraRadiusLerp","radius",t.radius,e,R.ANIMATIONTYPE_FLOAT,c))}t.animations.push(...o);const l=t.useAutoRotationBehavior;t.disableAutoRotationBehavior(),e.beginAnimation(t,0,n?120:60,!1,1,(()=>{t.animations=[],l&&t.enableAutoRotationBehavior()}))}function Y(e){return e*Math.PI/180}function Q(e,t,a,i,r,s=0,o=R.ANIMATIONLOOPMODE_CONSTANT){const n=new L;n.setEasingMode(C.EASINGMODE_EASEINOUT);const c=new R(e,t,60,r,o),l=[];return s>0&&l.push({frame:0,value:a}),l.push({frame:60*s,value:a}),l.push({frame:60*(s+1),value:i}),c.setKeys(l),c.setEasingFunction(n),c}class $ extends A{constructor(e,t,a,i,r,s,o,n){super(e,t,a,i,r,s,n),this.minZ=.01,this.maxZ=1e3*this.radius,this.lowerRadiusLimit=.01*this.radius,this.enableFramingBehavior(),this.upperRadiusLimit=1.5*this.radius,this.wheelPrecision=100/this.radius,this.pinchPrecision=300/this.radius,this.wheelDeltaPercentage=.01,this.pinchDeltaPercentage=.005,this.useNaturalPinchZoom=!0,o.camera.autoOrientation&&(this.alpha+=Math.PI),o&&(o.camera.limits.min.beta&&(this.lowerBetaLimit=o.camera.limits.min.beta),o.camera.limits.max.beta&&(this.upperBetaLimit=o.camera.limits.max.beta),o.camera.limits.min.alpha&&(this.lowerAlphaLimit=o.camera.limits.min.alpha),o.camera.limits.max.alpha&&(this.upperAlphaLimit=o.camera.limits.max.alpha),o.camera.limits.min.radius&&(this.lowerRadiusLimit=o.camera.limits.min.radius),o.camera.limits.max.radius&&(this.upperRadiusLimit=o.camera.limits.max.radius),o.camera.autoRotation.enabled&&this.enableAutoRotationBehavior(o.camera.autoRotation.idleTimeMs))}lastFocus=new y(0,0,0);getFramingBehavior(){return this.getBehaviorByName("Framing")}getAutoRotationBehavior(){const e=this.getBehaviorByName("AutoRotation");return e||void 0}enableFramingBehavior(){this.useFramingBehavior=!0;const e=this.getFramingBehavior();e.attach(this),e.framingTime=0,e.elevationReturnTime=-1,e.zoomStopsAnimation=!1,this.lowerRadiusLimit=null;const t=J(this._scene);return e.zoomOnBoundingInfo(t.min,t.max),this.wheelPrecision=100/this.radius,null===this.lowerRadiusLimit&&(this.lowerRadiusLimit=.1),this.lastFocus.copyFrom(this.target),e}rerunFramingBehavior(e){const t=this.getFramingBehavior();t.framingTime=800;const a=J(this._scene);t.zoomOnBoundingInfo(a.min,a.max,void 0,(()=>{e()})),t.framingTime=0}enableAutoRotationBehavior(e=5e3){this.useAutoRotationBehavior=!0;const t=this.getAutoRotationBehavior();t&&(t.idleRotationWaitTime=e)}disableAutoRotationBehavior(){this.useAutoRotationBehavior=!1}static create(e,t){e.activeCamera&&(e.activeCamera.dispose(),e.activeCamera=null);const a=J(e),i=a.max.subtract(a.min),r=a.min.add(i.scale(.5)),s=new $("ProductCamera",-Math.PI/2,Math.PI/2,1.5*i.length(),r,e,t);return s.panningInertia=0,s.panningOriginTarget.copyFrom(r),s.onAfterCheckInputsObservable.add((()=>{s.panningSensibility=1e3/i.length()})),e.activeCamera=s,s}}function J(e){const t=e.meshes.filter((e=>e.name.toLowerCase().endsWith("_t")||e.name.toLowerCase().includes("_t_")));return e.getWorldExtends((e=>e.isVisible&&e.isEnabled()&&(0===t.length||t.includes(e))))}const ee={albedoTexture:"albedoMapKey",bumpTexture:"normalMapKey",ambientTexture:"ambientMapKey",emissiveTexture:"emissionMapKey",opacityTexture:"alphaMapKey",metallicTexture:"metallicMapKey",refractionTexture:"refractionMapKey"};function te(e,t,a,i){["albedoTexture","bumpTexture","ambientTexture","emissiveTexture","opacityTexture","metallicTexture","refractionTexture"].forEach((r=>{!function(e,t,a,i,r){const s=ee[e];if(!s)throw new Error("Unexpected texture name encountered.");const o=t[s];o?i.addTextureTask(e,o,!1,!1):r&&a[e]&&(a[e]&&a[e].dispose(),a[e]=null,function(e,t){"opacityTexture"===e&&(t.useAlphaFromAlbedoTexture=!0);"metallicTexture"===e&&(t.useRoughnessFromMetallicTextureAlpha=!1,t.useRoughnessFromMetallicTextureGreen=!1,t.useMetallnessFromMetallicTextureBlue=!1);"refractionTexture"===e&&(t.subSurface.isRefractionEnabled=!1,t.subSurface.refractionIntensity=1)}(e,a))}(r,e,t,a,i)})),function(e,t){if(!e.clearCoat)return;e.clearCoat===_.RemoveWhenSelected?(t.clearCoat.isEnabled=!1,t.clearCoat.indexOfRefraction=1.5):e.clearCoat===_.ApplyWhenSelected&&(t.clearCoat.isEnabled=!0,t.clearCoat.indexOfRefraction=e.clearCoatIOR||t.clearCoat.indexOfRefraction)}(e,t)}function ae(e,t,a,i){"opacityTexture"===e&&(t.useAlphaFromAlbedoTexture=!1),"metallicTexture"===e&&(t.useRoughnessFromMetallicTextureAlpha=!1,t.useRoughnessFromMetallicTextureGreen=!0,t.useMetallnessFromMetallicTextureBlue=!0),"refractionTexture"===e&&(t.subSurface.isRefractionEnabled=!0,t.subSurface.refractionIntensity=a.refractionIntensity||1),t[e]=i}class ie{materialVariantMap=new Map;keysThatRemovedBaseModel=[];loadedContainerForKey=new Map;async applyMaterial(e,t,a,i,r){return new Promise((s=>{const o=e.materials.filter((e=>e.name===t)),n=this.materialVariantMap.get(t);if(this.materialVariantMap.set(t,{...n,...a}),0===o.length)return void s(void 0);const c=new P(e);c.useDefaultLoadingScreen=!1,o.forEach((e=>te(a,e,c,r))),c.onProgress=(e,t,a)=>{i&&i(e/t*100,100,a.name)},c.onFinish=e=>{e.forEach((e=>{const t=e;i&&i(100,100,e.name),o.forEach((i=>ae(e.name,i,a,t.texture)))})),s(void 0)},c.loadAsync()}))}async applyModel(e,t,a,i,r){if(i&&a&&!this.keysThatRemovedBaseModel.includes(t)&&this.keysThatRemovedBaseModel.push(t),!i){const a=this.keysThatRemovedBaseModel.includes(t);return this.loadedContainerForKey.get(t)?.removeAllFromScene(),e&&a&&await oe(e.metadata.baseModel,e),Promise.resolve()}const s=await U(i,e,r);if(this.loadedContainerForKey.has(t)&&this.loadedContainerForKey.get(t)?.removeAllFromScene(),a){(await U(e.metadata.baseModel,e)).removeAllFromScene()}s.addAllToScene(),this.loadedContainerForKey.set(t,s);const o=[];this.materialVariantMap.forEach((async(t,a)=>{o.push(this.applyMaterial(e,a,t))})),await Promise.all(o)}}var re=async(e,t)=>{const a=await t.createDefaultXRExperienceAsync({uiOptions:{sessionMode:"immersive-ar",referenceSpaceType:"local-floor",onError:e=>{console.log(e)}}}),i=a.baseExperience.featuresManager.enableFeature(E.Name,"latest",{disablePermanentHitTest:!0,enableTransientHitTest:!0,useReferenceSpace:!0});let r=null;i.onHitTestResultObservable.add((e=>{r=e.length?e[0]:void 0})),t.onPointerDown=()=>{if(r&&a.baseExperience.state===O.IN_XR){const e=t.getNodeByName("__root__");r.transformationMatrix.decompose(void 0,e.rotationQuaternion,e.position)}}};class se{loadProgress=new Map([["initialScene",0]]);materialReadyToLoadCallbacks=new Map;modelReadyToLoadCallbacks=new Map;focusLostNotified=!1;loadObservable=new w;focusLostObservable=new w;dynamicTextures=new Map;variantManager=new ie;constructor(e,t){this.configuration=new W(t);v.Configuration={decoder:{wasmUrl:"https://www.gstatic.com/draco/versioned/decoders/1.5.3/draco_wasm_wrapper_gltf.js",wasmBinaryUrl:"https://www.gstatic.com/draco/versioned/decoders/1.5.3/draco_decoder_gltf.wasm",fallbackUrl:"https://www.gstatic.com/draco/versioned/decoders/1.5.3/draco_decoder_gltf.js"}},e&&(e.getContext("webgl2")||e.getContext("webgl"));const a=console.log;console.log=()=>{};const i=e?new h(e,!0,{premultipliedAlpha:!1,preserveDrawingBuffer:!!t?.backgroundImage,audioEngine:!1,stencil:this.configuration.highlights.enabled,forceSRGBBufferSupportState:!0}):new m;console.log=a,i.hideLoadingUI(),window.addEventListener("resize",this.fireResizeEvent.bind(this)),this.engine=i,this.scene=new M(i)}registerFocusLostListener(e){this.focusLostObservable.add(e)}unregisterFocusLostListener(e){this.focusLostObservable.removeCallback(e)}registerLoadProgressListener(e){this.loadObservable.add(e),e(this.getLoadListenerEvent())}unregisterLoadProgressListener(e){this.loadObservable.removeCallback(e)}registerView(e){const t=e.height,a=e.width;this.engine.registerView(e),e.setAttribute("height",t.toString()),e.setAttribute("width",a.toString()),this.orbitEnabled()||this.setCameraState(D.Pan)}getNumViewports(){return this.engine.views?.length||0}unregisterView(e){this.engine.unRegisterView(e),this.engine.inputElement=null}shutdown(){this.engine&&this.engine.dispose(),window.removeEventListener("resize",this.fireResizeEvent)}getSceneInitializationProgress(){return this.loadProgress.get("initialScene")}async initialize(e,t){if(this.scene.clearColor=this.configuration.scene.clearColor,this.scene.metadata={baseModel:e},this.scene.environmentTexture=g.CreateFromPrefilteredData(this.configuration.scene.environmentFile,this.scene),e){const t=99;await oe(e,this.scene,(e=>{this.loadProgress.set("initialScene",e.loaded*t/e.total),this.notifyLoadHandlers()}))}this.configuration.highlights.enabled&&this.scene.meshes.forEach((e=>{"targetcube_t"!==e.name&&"backgroundShell"!==e.name&&(e.isPickable=!0,e.actionManager||(e.actionManager=new c(this.scene)),e.actionManager.registerAction(new l(c.OnPointerOutTrigger,(()=>{this.setHighlights([])}))),e.actionManager.registerAction(new l(c.OnPointerOverTrigger,(e=>{if(e.meshUnderPointer){const t=e.meshUnderPointer.material;t&&this.setHighlights([t])}}))))}));const a=$.create(this.scene,this.configuration),i=t?.getAll()||new Map;G(this.scene,i,this.dynamicTextures);if(this.scene.materials.some((e=>"emissiveTexture"in e&&null!==e.emissiveTexture))){new u("GlowLayer",this.scene).intensity=.5}X(this.scene),this.engine.runRenderLoop((()=>{if(!this.engine.views)return;const e=this.engine.views[0],t=this.engine.inputElement;(!t||e&&t&&t.id!==e.target.id)&&this.reattachControls(e.target),i.forEach(((e,t)=>{const a=this.dynamicTextures.get(t);a&&e.getStaticContextDirty()&&a.isReady()&&(a.update(!1),e.setStaticContextDirty(!1))})),this.configuration.scene.transparentBackground&&this.engine.views.forEach((e=>{const t=this.engine.getRenderingCanvas();e.target.getContext("2d").clearRect(0,0,t.width,t.height)})),this.scene.render(),100!==this.getSceneInitializationProgress()&&(this.loadProgress.set("initialScene",100),this.materialReadyToLoadCallbacks.forEach(((e,t)=>{e.forEach(((e,a)=>{this.applyMaterialVariant(t,a,e)}))})),this.materialReadyToLoadCallbacks.clear(),this.modelReadyToLoadCallbacks.forEach((e=>{e(this.scene)})),this.modelReadyToLoadCallbacks.clear(),this.queuedModelAnimation&&(this.executeModelAnimation(this.queuedModelAnimation),this.queuedModelAnimation=void 0),this.queuedCameraAnimation&&(this.executeCameraAnimation(this.queuedCameraAnimation),this.queuedCameraAnimation=void 0),this.notifyLoadHandlers()),a.target.equalsWithEpsilon(a.lastFocus,.1)||this.focusLostNotified||(this.focusLostObservable.notifyObservers(void 0),this.focusLostNotified=!0)}))}executeModelAnimation(e){100===this.getSceneInitializationProgress()?K(this.scene,e.loop,e.to,e.from):this.queuedModelAnimation=e}executeCameraAnimation(e){100===this.getSceneInitializationProgress()&&this.scene.activeCamera?Z(this.scene,this.scene.activeCamera,e):this.queuedCameraAnimation=e}getCameraPose(){if(this.scene){const e=this.scene.activeCamera;if(e)return{lonDeg:Math.round(180*e.alpha/Math.PI),latDeg:Math.round(180*e.beta/Math.PI),radius:Math.round(1e4*(e.radius+Number.EPSILON))/1e4,target:{x:e.target.x,y:e.target.y,z:e.target.z}}}}setCameraPose(e){if(this.scene){const t=this.scene.activeCamera;t&&(t.target=new y(e.target.x,e.target.y,e.target.z),t.radius=e.radius,t.alpha=e.latDeg,t.beta=e.lonDeg)}}async applyMaterialVariant(e,t,a,i){if(100===this.getSceneInitializationProgress())await this.variantManager.applyMaterial(this.scene,e,a,((e,t,a)=>{this.loadProgress.set(`key_${a}`,e/t*100),this.notifyLoadHandlers()}),i);else if(this.materialReadyToLoadCallbacks.has(e)){this.materialReadyToLoadCallbacks.get(e)?.set(t,a)}else{this.materialReadyToLoadCallbacks.set(e,new Map);this.materialReadyToLoadCallbacks.get(e)?.set(t,a)}}async applyModelVariant(e,a,i){100===this.getSceneInitializationProgress()?(await this.variantManager.applyModel(this.scene,e,i||!1,a.model,(t=>{this.loadProgress.set(e,100*t.loaded/t.total),this.notifyLoadHandlers()})),this.scene.materials.forEach((e=>{if(e&&0===e.getBindedMeshes().length){const a=e instanceof t&&!(e.albedoTexture instanceof p);e.dispose(!1,a)}})),G(this.scene,a.contextService.getAll(),this.dynamicTextures),X(this.scene)):this.modelReadyToLoadCallbacks.set(e,(()=>{this.applyModelVariant(e,a,i)}))}setCameraState(e){if(!this.engine?.views||!this.engine?.views[0])throw new Error("No views attached, camera state requires a view to attach controls onto.");e===D.Orbit?this.reattachControls(this.engine.views[0].target,2):this.reattachControls(this.engine.views[0].target,0)}animateToLastCameraFocus(){return new Promise((e=>{const t=this.scene.activeCamera,a=this.configuration;t.rerunFramingBehavior((()=>{this.focusLostNotified=!1,a.camera.limits.min.radius&&(t.lowerRadiusLimit=a.camera.limits.min.radius),a.camera.limits.max.radius&&(t.upperRadiusLimit=a.camera.limits.max.radius),e()}))}))}setAutoRotation(e){const t=this.scene.activeCamera;this.configuration.camera.autoRotation.enabled&&t&&(e?t.enableAutoRotationBehavior(this.configuration.camera.autoRotation.idleTimeMs):t.disableAutoRotationBehavior())}getCurrentConfiguration(){return this.configuration.options}async renderSceneScreenshot(e,t){const a=this.scene.activeCamera;if(!a)throw new Error("Missing product camera, cannot render screenshot!");var i;(i=a).getScene().stopAnimation(i),i.animations=[];const r=a.alpha,s=a.beta,o=a.radius,n=t.latDeg*Math.PI/180,c=t.lonDeg*Math.PI/180;a.alpha=c,a.beta=n,a.radius=t.radius||a.radius;const l=await x.CreateScreenshotUsingRenderTargetAsync(this.engine,a,e,"image/png",2,!0);return a.alpha=r,a.beta=s,a.radius=o,l}orbitEnabled(){const e=this.configuration;if(!e)return!0;const t=e.camera.limits.min.alpha,a=e.camera.limits.max.alpha,i=e.camera.limits.min.beta,r=e.camera.limits.max.beta;if(void 0===t||void 0===a||void 0===i||void 0===r)return!0;const s=[i,r],o=[t,a].every((e=>e===t)),n=s.every((e=>e===i));return!o&&!n}fireResizeEvent(){this.getNumViewports()>0&&this.engine.resize()}onMaterialSelected(e){this.scene.meshes.forEach((t=>{"targetcube_t"!==t.name&&"backgroundShell"!==t.name&&(t.actionManager||(t.actionManager=new c(this.scene)),t.actionManager.registerAction(new l(c.OnPickDownTrigger,(t=>{if(t.meshUnderPointer){const a=t.meshUnderPointer.material;a&&e({id:a.id,name:a.name})}}))))}))}listMaterials(){const e=this.scene?.materials;return e?e.map((e=>({id:e.id,name:e.name}))):[]}setHighlights(e,t){0===e.length&&(this.highlightLayer?.dispose(),this.highlightLayer=void 0),this.highlightLayer||(this.highlightLayer=new d("highlights",this.scene,{isStroke:!0,blurVerticalSize:.85,blurHorizontalSize:.85}),this.highlightLayer.innerGlow=!0,this.highlightLayer.outerGlow=!1),this.highlightLayer.removeAllMeshes();const a=t?new f(t[0],t[1],t[2]).toLinearSpace():void 0;e.forEach((e=>{const t=this.scene.materials.find((t=>t.name===e.name&&t.id===e.id));t&&t.getBindedMeshes().forEach((e=>this.highlightLayer?.addMesh(e,a||f.FromHexString("#fcba03"))))}))}initXRExperience(e){re(0,this.scene)}reattachControls(e,t=2){this.scene.detachControl(),this.engine.inputElement=e;const a=this.scene.activeCamera;if(a){a.attachControl(!0,!1,t);a.inputs.attached.pointers.multiTouchPanning=!1}this.scene.attachControl(!0,!0,!0)}getLoadListenerEvent(){const e=Array.from(this.loadProgress.values()).filter((e=>e<100)),t=e.reduce(((e,t)=>e+t),0)/e.length||0;return{loadValue:0===e.length?100:t,sceneInitialized:100===this.getSceneInitializationProgress()}}notifyLoadHandlers(){this.loadObservable.notifyObservers(this.getLoadListenerEvent())}}async function oe(e,t,a){(await U(e,t,a)).addAllToScene()}export{D as ProductCameraRig,_ as MaterialEffectMode,se as SpiffCommerce3DPreviewService,oe as createBaseModel,B as RenderingConfiguration,F as REFLECTION_PROBE_RESOLUTION};
2
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1,522 @@
1
+ import { ISceneLoaderProgressEvent } from "@babylonjs/core/Loading/sceneLoader";
2
+ import { Scene } from "@babylonjs/core/scene";
3
+ /**
4
+ * Defines the different behaviors supported by the camera system
5
+ * for control when viewing a product.
6
+ */
7
+ export enum ProductCameraRig {
8
+ Orbit = 0,
9
+ Pan = 1
10
+ }
11
+ /**
12
+ * Details relating to a model for use in the preview.
13
+ */
14
+ export type ModelDetails = {
15
+ readonly model?: string;
16
+ readonly contextService: RenderableContextService;
17
+ };
18
+ /**
19
+ * Identical to CameraAnimation typing, however the
20
+ * target is always available and hence is not optional.
21
+ */
22
+ export type CameraPose = {
23
+ readonly lonDeg: number;
24
+ readonly radius: number;
25
+ readonly latDeg: number;
26
+ readonly target: {
27
+ readonly x: number;
28
+ readonly y: number;
29
+ readonly z: number;
30
+ };
31
+ };
32
+ export type ThreeDPreviewService = {
33
+ /**
34
+ * Allows listeners to be aware of the camera losing focus of the
35
+ * main product.
36
+ * @param listener A function to be called when focus is lost.
37
+ */
38
+ registerFocusLostListener(listener: () => void): void;
39
+ /**
40
+ * Removes a listener from the focusLost observers. The listener will
41
+ * no longer be notified
42
+ * @param listener The listener to remove.
43
+ */
44
+ unregisterFocusLostListener(listener: () => void): void;
45
+ /**
46
+ * Providers listeners with information about load progress when
47
+ * the preview is loading scenes.
48
+ * @param listener A function to get load progress updates
49
+ */
50
+ registerLoadProgressListener(listener: (e: LoadProgressEventData) => void): void;
51
+ /**
52
+ * Allows you to pass any function that originally called registerLoadProgressListener()
53
+ * to have it excluded from load progress updates.
54
+ * If the function was never registered this call has no effect.
55
+ * @param listener The listener to exclude from load progress.
56
+ */
57
+ unregisterLoadProgressListener(listener: (e: LoadProgressEventData) => void): void;
58
+ /**
59
+ * Request that the scene renders to a given canvas
60
+ * @param canvas The canvas we should render to.
61
+ */
62
+ registerView(canvas: HTMLCanvasElement): void;
63
+ /**
64
+ * Returns the number of active viewers of the scene. Useful for
65
+ * avoiding unnecessary rendering when there are no active viewers.
66
+ */
67
+ getNumViewports(): number;
68
+ /**
69
+ * Tells babylon that we no longer want the given canvas to be rendered to.
70
+ * @param canvas The canvas to be excluded from rendering.
71
+ */
72
+ unregisterView(canvas: HTMLCanvasElement): void;
73
+ /**
74
+ * Shutdown the preview engine. Noop if the engine is not initialized.
75
+ */
76
+ shutdown(): void;
77
+ /**
78
+ * Initialize the scene. Also initialize the engine, if it hasn't been done already.
79
+ */
80
+ initialize(src: string, contextService?: RenderableContextService): Promise<void>;
81
+ /**
82
+ * Executes an animation in the currently loaded scene.
83
+ * @param animation The current animation track to run.
84
+ */
85
+ executeModelAnimation(animation: ModelAnimation): void;
86
+ /**
87
+ * Executes an animation of the camera.
88
+ * @param animation The animation to execute.
89
+ */
90
+ executeCameraAnimation(animation: CameraAnimation): void;
91
+ /**
92
+ * Returns the values of the Arc Rotate Camera
93
+ */
94
+ getCameraPose(): CameraPose | undefined;
95
+ /**
96
+ * Sets the values of the Arc Rotate Camera
97
+ */
98
+ setCameraPose(cameraPose: CameraPose): void;
99
+ /**
100
+ * Applies a given material modifier to a target material in the scene.
101
+ * @param targetMaterial The material to target.
102
+ * @param key A unique key used to identify this action.
103
+ * @param material The material modifier to apply.
104
+ */
105
+ applyMaterialVariant(targetMaterial: string, key: string, material: MaterialResource, removeWhenUndefined?: boolean): Promise<void>;
106
+ /**
107
+ * Applies a given model variant to the scene.
108
+ * @param key A unique key used to identify this action.
109
+ * @param model modelDetails -> An asset containing a model file to be loaded into the scene.
110
+ * @param layouts modelDetails -> The layouts of the workflow, used for applying dynamic textures.
111
+ */
112
+ applyModelVariant(key: string, modelDetails: ModelDetails, replaceProductModel: boolean): Promise<void>;
113
+ /**
114
+ * Controls the current control state of the camera.
115
+ * @param rigType The control type to use.
116
+ */
117
+ setCameraState(rigType: ProductCameraRig): void;
118
+ /**
119
+ * Restores the product camera to it's last set focus point. If the user has
120
+ * been panning this will animate the camera to the original focus point. If the camera is still
121
+ * focused on it's origin point this function is a noop.
122
+ */
123
+ animateToLastCameraFocus(): Promise<void>;
124
+ /**
125
+ * When configuration has allowed for auto rotation we
126
+ * can pause the rotation via this function.
127
+ * @param shouldAutoRotate When true rotation is running, paused otherwise.
128
+ */
129
+ setAutoRotation(shouldAutoRotate: boolean): void;
130
+ /**
131
+ * Get current load progress for the scene.
132
+ */
133
+ getSceneInitializationProgress(): number;
134
+ /**
135
+ * Returns the current configuration object applied to the scene.
136
+ */
137
+ getCurrentConfiguration(): PreviewOptions | undefined;
138
+ /**
139
+ * Takes a screenshot of the scene using a given
140
+ * camera animation otherwise using the existing orientation
141
+ * of the camera in the scene. A resolution must be provided
142
+ * to render the scene at.
143
+ */
144
+ renderSceneScreenshot(resolution: number, cameraAnimation: CameraAnimation): Promise<string>;
145
+ /**
146
+ * Returns true when the current configuration allows the user
147
+ * to rotate around the product.
148
+ */
149
+ orbitEnabled(): boolean;
150
+ /**
151
+ * When called will trigger the internal engine to match the current
152
+ * canvas size. This ensures the image renders correctly in the view and
153
+ * also prevents performance problems.
154
+ */
155
+ fireResizeEvent(): void;
156
+ /**
157
+ * A callback when the user clicks in the scene and a material is hit.
158
+ */
159
+ onMaterialSelected(cb: (material: MaterialHandle) => void): void;
160
+ /**
161
+ * Designed for use when utilizing the 3D preview in an editor format.
162
+ * List named materials that are available in the scene.
163
+ */
164
+ listMaterials(): readonly MaterialHandle[];
165
+ /**
166
+ * Designed for use when utilizing the 3D preview in an editor format.
167
+ * Given a list of material names, highlights the associated meshes in the scene.
168
+ */
169
+ setHighlights(materials: readonly MaterialHandle[], color?: readonly [number, number, number]): void;
170
+ };
171
+ /**
172
+ * Represents a service capable of managing and returning contexts that
173
+ * can be used for rendering to textures in the 3D preview.
174
+ */
175
+ export type RenderableContextService = {
176
+ /**
177
+ * Returns all managed renderable contexts.
178
+ */
179
+ getAll(): ReadonlyMap<string, RenderableContext>;
180
+ };
181
+ /**
182
+ * A renderable context represents the relationship of a texture in the 3D preview
183
+ * with an external canvas. This context allows external clients to render to a texture
184
+ * in the 3D preview with a simple interface.
185
+ */
186
+ export type RenderableContext = {
187
+ /**
188
+ * A unique identifier for this renderable context.
189
+ */
190
+ getID(): string;
191
+ /**
192
+ * A name for this renderable.
193
+ */
194
+ getName(): string;
195
+ /**
196
+ * Sets the render context associated to this renderable.
197
+ * @param ctx The context to use for rendering.
198
+ */
199
+ setStaticContext(ctx: CanvasRenderingContext2D): void;
200
+ /**
201
+ * Get the render context associated to this renderable.
202
+ */
203
+ getStaticContext(): CanvasRenderingContext2D | undefined;
204
+ /**
205
+ * Sets whether or not this renderable is dirty and will need re-rendering.
206
+ * @param value The new value
207
+ */
208
+ setStaticContextDirty(value: boolean): void;
209
+ /**
210
+ * When this context has been set as dirty, returns true.
211
+ */
212
+ getStaticContextDirty(): boolean;
213
+ /**
214
+ * A timestamp for the last successful render of the context.
215
+ */
216
+ getLastCompletedStaticRender(): number | undefined;
217
+ };
218
+ export type LoadProgressEventData = {
219
+ /**
220
+ * The total load value of the scene, this is an average of all
221
+ * 'in progress' loading events. when all events are fully loaded this value will be 100.
222
+ */
223
+ readonly loadValue: number;
224
+ /**
225
+ * This value is true when the base model and scene have been initialized.
226
+ */
227
+ readonly sceneInitialized: boolean;
228
+ };
229
+ /**
230
+ * Used to specify the behavior of a material effect such as clearcoat, sheen and translucency.
231
+ */
232
+ export enum MaterialEffectMode {
233
+ /**
234
+ * When a material variant effect specifies 'None' the effect doesn't change in any way. This is the default behavior.
235
+ */
236
+ None = "None",
237
+ /**
238
+ * When a material variant effect specifies 'RemoveWhenSelected' the effect is removed.
239
+ */
240
+ RemoveWhenSelected = "RemoveWhenSelected",
241
+ /**
242
+ * When a material variant effect specifies 'ApplyWhenSelected' the effect is enabled.
243
+ */
244
+ ApplyWhenSelected = "ApplyWhenSelected"
245
+ }
246
+ /**
247
+ * Represents a material resource that can be additively applied to
248
+ * a material targeted in the scene.
249
+ */
250
+ export type MaterialResource = {
251
+ /**
252
+ * A unique identified for this material.
253
+ */
254
+ id: string;
255
+ /**
256
+ * The name of this material
257
+ */
258
+ name: string;
259
+ /**
260
+ * Defines the base color of a surface before any other calculations are made.
261
+ */
262
+ albedoMapKey?: string;
263
+ albedoKey?: string;
264
+ /**
265
+ * Defines the transparency of a surface.
266
+ */
267
+ alphaMapKey?: string;
268
+ alphaKey?: string;
269
+ /**
270
+ * Defines shadowing on a surface.
271
+ */
272
+ ambientMapKey?: string;
273
+ ambientKey?: string;
274
+ /**
275
+ * Defines the amount of light being emitted from a surface.
276
+ */
277
+ emissionMapKey?: string;
278
+ emissionKey?: string;
279
+ /**
280
+ * Identical to roughness.
281
+ */
282
+ metallicMapKey?: string;
283
+ metallicKey?: string;
284
+ /**
285
+ * Defines the direction light will bounce in when it hits a point on a surface.
286
+ */
287
+ normalMapKey?: string;
288
+ normalKey?: string;
289
+ /**
290
+ * Used to define how smooth a surface is.
291
+ */
292
+ roughnessMapKey?: string;
293
+ roughnessKey?: string;
294
+ /**
295
+ * Used to define refreaction of light on a surface.
296
+ */
297
+ refractionMapKey?: string;
298
+ refractionKey?: string;
299
+ /**
300
+ * The intensity of refraction, when refraction is enabled via a texture.
301
+ */
302
+ refractionIntensity?: number;
303
+ /**
304
+ * When enabled the material will be displayed with a clearcoat affect for simulating coated plastic surfaces.
305
+ */
306
+ clearCoat: MaterialEffectMode;
307
+ /**
308
+ * Index of refraction when clear coat is enabled.
309
+ */
310
+ clearCoatIOR?: number;
311
+ /**
312
+ * The date that this material resource was created
313
+ */
314
+ createdAt: string;
315
+ /**
316
+ * The date that this material resource was last updated.
317
+ */
318
+ updatedAt: string;
319
+ };
320
+ /**
321
+ * Represents a handle to a material in the 3D scene. The underlying complexity of materials is abstracted
322
+ * away so the client doesn't need to know anything more than the ID they're given and the name.
323
+ */
324
+ export type MaterialHandle = {
325
+ /**
326
+ * The identifier for the material.
327
+ */
328
+ readonly id: string;
329
+ /**
330
+ * The human readable name for the material.
331
+ */
332
+ readonly name: string;
333
+ };
334
+ /**
335
+ * Settings related to the 3D preview.
336
+ */
337
+ export type PreviewOptions = {
338
+ /**
339
+ * The color expected to be seen in the background of the product. Expects a hexadecimal value.
340
+ */
341
+ readonly backgroundColor?: string;
342
+ /**
343
+ * Image to be used as a background when running withh transparency, the image
344
+ * will be scaled and centered to fill the preview based on aspect ratio.
345
+ */
346
+ readonly backgroundImage?: string;
347
+ /**
348
+ * The closest zoom the camera can achieve to the product.
349
+ */
350
+ readonly maxZoomOverride?: number;
351
+ /**
352
+ * The furthest zoom the camera can achieve to the product.
353
+ */
354
+ readonly minZoomOverride?: number;
355
+ /**
356
+ * The environment file used to calculate product lighting.
357
+ */
358
+ readonly environmentFile?: string;
359
+ /**
360
+ * The lowest point, vertically, that the camera can rotate to.
361
+ * https://doc.babylonjs.com/divingDeeper/cameras/camera_introduction
362
+ */
363
+ readonly lowerBetaLimitDeg?: number;
364
+ /**
365
+ * The highest point, vertically, that the camera can rotate to.
366
+ * https://doc.babylonjs.com/divingDeeper/cameras/camera_introduction
367
+ */
368
+ readonly upperBetaLimitDeg?: number;
369
+ /**
370
+ * The leftmost point, horizontally, that the camera can rotate to.
371
+ * https://doc.babylonjs.com/divingDeeper/cameras/camera_introduction
372
+ */
373
+ readonly lowerAlphaLimitDeg?: number;
374
+ /**
375
+ * The rightmost point, horizontally, that the camera can rotate to.
376
+ * https://doc.babylonjs.com/divingDeeper/cameras/camera_introduction
377
+ */
378
+ readonly upperAlphaLimitDeg?: number;
379
+ /**
380
+ * When set the product while rotate slowly
381
+ */
382
+ readonly autoRotation?: boolean;
383
+ /**
384
+ * Time in milliseconds before the product starts rotating after a user input has taken control.
385
+ */
386
+ readonly idleTimeBeforeRotation?: number;
387
+ /**
388
+ * When set the 3D preview won't attempt to orient the product automatically to its front view at load.
389
+ */
390
+ readonly disableAutomaticOrientation?: boolean;
391
+ /**
392
+ * When true the action bar won't be displayed to the user.
393
+ */
394
+ readonly disableActionBar?: boolean;
395
+ /**
396
+ * When set, mousing over the model in this preview will highlight the associated mesh/material.
397
+ * When layout contexts are provided, only the materials with matching names will highlight.
398
+ */
399
+ readonly highlightOnMaterialHover?: boolean;
400
+ /**
401
+ * Sets the color of highlights when enabled. Expects hexadecimal value.
402
+ */
403
+ readonly highlightColor?: string;
404
+ };
405
+ /**
406
+ * Defines an animation to be play on a product.
407
+ */
408
+ export type ModelAnimation = {
409
+ /**
410
+ * A value it seconds along the animation timeline to begin at.
411
+ */
412
+ readonly from: number;
413
+ /**
414
+ * A value in seconds along the animation timeline to end at.
415
+ */
416
+ readonly to?: number;
417
+ /**
418
+ * When true the animation will loop. The only behavior currently is to reset
419
+ * back to from but we could have it bounce back and forth and/or follow a curve.
420
+ */
421
+ readonly loop: boolean;
422
+ };
423
+ /**
424
+ * A CameraAnimation specifies a discrete state that the camera should
425
+ * animate to. This state represents the final position of the camera after animations have run.
426
+ */
427
+ export type CameraAnimation = {
428
+ /**
429
+ * The longitude in degrees the camera should animate to.
430
+ */
431
+ readonly lonDeg: number;
432
+ /**
433
+ * The latitude in degrees the camera should animate to.
434
+ */
435
+ readonly latDeg: number;
436
+ /**
437
+ * An optional target for the camera to focus on in the scene.
438
+ */
439
+ readonly target?: {
440
+ readonly x: number;
441
+ readonly y: number;
442
+ readonly z: number;
443
+ };
444
+ /**
445
+ * A value in scene units specifying camera distance from the target.
446
+ */
447
+ readonly radius?: number;
448
+ };
449
+ /**
450
+ * Represents the dimensions of a texture, enforcing power of two numbers.
451
+ */
452
+ type RenderDimensions = {
453
+ readonly width: PowerOfTwoNumber;
454
+ readonly height: PowerOfTwoNumber;
455
+ };
456
+ /**
457
+ * A class containing largely static configuration information.
458
+ */
459
+ export class RenderingConfiguration {
460
+ /**
461
+ * Returns the resolution expected for generated textures.
462
+ */
463
+ static getDynamicTextureResolution(): RenderDimensions;
464
+ /**
465
+ * Returns true when textures should generate mip maps
466
+ */
467
+ static shouldMipMap(): boolean;
468
+ /**
469
+ * Returns true when multithreaded rendering is supported.
470
+ */
471
+ static offscreenRenderingSupported(): boolean;
472
+ /**
473
+ * Returns the resolution expected for mirror textures.
474
+ */
475
+ static getMirrorTextureResolution(): PowerOfTwoNumber;
476
+ }
477
+ export const REFLECTION_PROBE_RESOLUTION = 128;
478
+ export type PowerOfTwoNumber = 128 | 256 | 512 | 1024 | 2048 | 4096 | 8192;
479
+ /**
480
+ * An example implementation of the ThreeDPreviewService interface. The inclusion of 3D previews
481
+ * is designed to be optional, anyone can come along and implement their own 3D preview service or
482
+ * they can use this one to get things running more quickly.
483
+ */
484
+ export class SpiffCommerce3DPreviewService implements ThreeDPreviewService {
485
+ constructor(canvas?: HTMLCanvasElement, options?: PreviewOptions);
486
+ registerFocusLostListener(listener: () => void): void;
487
+ unregisterFocusLostListener(listener: () => void): void;
488
+ registerLoadProgressListener(listener: (e: LoadProgressEventData) => void): void;
489
+ unregisterLoadProgressListener(listener: (e: LoadProgressEventData) => void): void;
490
+ registerView(canvas: HTMLCanvasElement): void;
491
+ getNumViewports(): number;
492
+ unregisterView(canvas: HTMLCanvasElement): void;
493
+ shutdown(): void;
494
+ getSceneInitializationProgress(): number;
495
+ initialize(src?: string, contextService?: RenderableContextService): Promise<void>;
496
+ executeModelAnimation(animation: ModelAnimation): void;
497
+ executeCameraAnimation(animation: CameraAnimation): void;
498
+ getCameraPose(): CameraPose | undefined;
499
+ setCameraPose(cameraPose: CameraPose): void;
500
+ applyMaterialVariant(targetMaterial: string, key: string, material: MaterialResource, removeWhenUndefined?: boolean): Promise<void>;
501
+ applyModelVariant(key: string, modelDetails: ModelDetails, replaceProductModel: boolean): Promise<void>;
502
+ setCameraState(rigType: ProductCameraRig): void;
503
+ animateToLastCameraFocus(): Promise<void>;
504
+ setAutoRotation(shouldAutoRotate: boolean): void;
505
+ getCurrentConfiguration(): PreviewOptions | undefined;
506
+ renderSceneScreenshot(resolution: number, camAnim: CameraAnimation): Promise<string>;
507
+ orbitEnabled(): boolean;
508
+ fireResizeEvent(): void;
509
+ onMaterialSelected(cb: (material: MaterialHandle) => void): void;
510
+ listMaterials(): readonly MaterialHandle[];
511
+ setHighlights(materials: readonly MaterialHandle[], color?: readonly [number, number, number]): void;
512
+ initXRExperience(buttonEl: HTMLElement): void;
513
+ }
514
+ /**
515
+ * Adds a tags a base mesh to the scene.
516
+ * TODO: Move this to another file with other creation/initialization functionality?
517
+ * @param src A url to a valid glb scene
518
+ * @param progressHandler A handler for load progress events.
519
+ */
520
+ export function createBaseModel(src: string, scene: Scene, progressHandler?: (event: ISceneLoaderProgressEvent) => void): Promise<void>;
521
+
522
+ //# sourceMappingURL=types.d.ts.map
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@spiffcommerce/preview",
3
+ "version": "2.0.0",
4
+ "description": "An internal implementation of the ThreeDPreviewService interface used by Spiff Commerce",
5
+ "source": "src/index.ts",
6
+ "main": "dist/main.js",
7
+ "module": "dist/module.js",
8
+ "types": "dist/types.d.ts",
9
+ "license": "UNLICENSED",
10
+ "scripts": {
11
+ "build": "parcel build",
12
+ "test": "jest && eslint src --ext .ts",
13
+ "prepare": "yarn build"
14
+ },
15
+ "sideEffects": true,
16
+ "dependencies": {
17
+ "@babylonjs/core": "^5.26.1",
18
+ "@babylonjs/loaders": "^5.26.1",
19
+ "@swc/helpers": "^0.4.11",
20
+ "babylonjs-gltf2interface": "^5.26.1"
21
+ },
22
+ "devDependencies": {
23
+ "@parcel/packager-ts": "2.7.0",
24
+ "@parcel/transformer-typescript-tsc": "^2.7.0",
25
+ "@parcel/transformer-typescript-types": "^2.7.0",
26
+ "@storybook/addon-actions": "^6.5.12",
27
+ "@storybook/addon-essentials": "^6.5.12",
28
+ "@storybook/addon-interactions": "^6.5.12",
29
+ "@storybook/addon-links": "^6.5.12",
30
+ "@storybook/builder-webpack5": "^6.5.12",
31
+ "@storybook/manager-webpack5": "^6.5.12",
32
+ "@storybook/react": "^6.5.12",
33
+ "@storybook/testing-library": "^0.0.13",
34
+ "@types/jest": "^29.0.3",
35
+ "@types/node": "^18.7.18",
36
+ "@typescript-eslint/eslint-plugin": "^5.37.0",
37
+ "@typescript-eslint/parser": "^5.37.0",
38
+ "canvg": "https://github.com/spiffdev/canvg.git#03bcd151b12441e88ecb552bb658356f5bbe92c4",
39
+ "eslint": "^8.23.1",
40
+ "eslint-config-prettier": "^8.5.0",
41
+ "eslint-plugin-eslint-comments": "^3.2.0",
42
+ "eslint-plugin-import": "^2.26.0",
43
+ "eslint-plugin-storybook": "^0.6.4",
44
+ "jest": "^29.0.3",
45
+ "jest-environment-jsdom": "^29.0.3",
46
+ "parcel": "^2.7.0",
47
+ "prettier": "^2.7.1",
48
+ "react": "^18.2.0",
49
+ "react-dom": "^18.2.0",
50
+ "ts-jest": "^29.0.3",
51
+ "typescript": "4.7.2"
52
+ },
53
+ "targets": {
54
+ "main": {
55
+ "optimize": true
56
+ },
57
+ "module": {
58
+ "optimize": true
59
+ }
60
+ },
61
+ "files": [
62
+ "dist/main.js",
63
+ "dist/module.js",
64
+ "dist/types.d.ts"
65
+ ],
66
+ "prettier": {
67
+ "singleQuote": true
68
+ }
69
+ }