UNPKG

physics-glass-effects

Version:

Physics-based glass effects using WebGL with real optical science - works with React, Vue, Next.js, and vanilla JS

3 lines (2 loc) 21.5 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e={water:{name:"Water",refractionIndex:1.33,dispersion:.01,description:"Clear water with minimal dispersion"},crownGlass:{name:"Crown Glass",refractionIndex:1.52,dispersion:.02,description:"Standard optical glass used in windows and lenses"},flintGlass:{name:"Flint Glass",refractionIndex:1.65,dispersion:.05,description:"Dense glass with high dispersion for prisms"},diamond:{name:"Diamond",refractionIndex:2.42,dispersion:.08,description:"Extremely high refraction creating brilliant effects"},acrylic:{name:"Acrylic",refractionIndex:1.49,dispersion:.015,description:"Lightweight plastic with glass-like properties"}};class n extends Error{constructor(e,n){super(e),this.code=n,this.name="PhysicsGlassError"}}const t={WEBGL_NOT_SUPPORTED:"WEBGL_NOT_SUPPORTED",CANVAS_NOT_FOUND:"CANVAS_NOT_FOUND",SHADER_COMPILATION_FAILED:"SHADER_COMPILATION_FAILED",TEXTURE_LOAD_FAILED:"TEXTURE_LOAD_FAILED",INVALID_CONFIGURATION:"INVALID_CONFIGURATION"};function i(){try{const e=document.createElement("canvas");return!!(e.getContext("webgl")||e.getContext("experimental-webgl"))}catch(e){return!1}}function r(e,i,r){const s=e.createShader(i);if(!s)throw new n("Failed to create shader",t.SHADER_COMPILATION_FAILED);if(e.shaderSource(s,r),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS)){const i=e.getShaderInfoLog(s);throw e.deleteShader(s),new n(`Shader compilation failed: ${i}`,t.SHADER_COMPILATION_FAILED)}return s}function s(e,i){const r=e.createTexture();if(!r)throw new n("Failed to create texture",t.TEXTURE_LOAD_FAILED);return e.bindTexture(e.TEXTURE_2D,r),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),r}function o(e,i){return new Promise((r,o)=>{const a=new Image;a.crossOrigin="anonymous",a.onload=()=>{try{const n=s(e,a);r(n)}catch(e){o(e)}},a.onerror=()=>{o(new n(`Failed to load image: ${i}`,t.TEXTURE_LOAD_FAILED))},a.src=i})}const a={shape:"sphere",size:.15,refractionIndex:1.5,dispersion:.03,thickness:.3,backgroundPattern:"stripes",backgroundTexture:"",mouse:{enabled:!0,followCursor:!0,centerX:.5,centerY:.5},animation:{enabled:!0,speed:1,surfaceRipples:!0},performance:{pixelRatio:window.devicePixelRatio||1,antialias:!0,preserveDrawingBuffer:!1,premultipliedAlpha:!1},onReady:()=>{},onError:()=>{},onShapeChange:()=>{},onMaterialChange:()=>{}};class c{constructor(e,i={}){if(this.webglState=null,this.animationId=null,this.isDestroyed=!1,this.time=0,this.mousePos={x:.5,y:.5},this.handleMouseMove=e=>{if(!this.config.mouse.followCursor)return;const n=this.canvas.getBoundingClientRect();this.mousePos.x=(e.clientX-n.left)/n.width,this.mousePos.y=1-(e.clientY-n.top)/n.height,this.uniforms.mousePos=[this.mousePos.x,this.mousePos.y]},this.handleMouseLeave=()=>{this.mousePos.x=this.config.mouse.centerX,this.mousePos.y=this.config.mouse.centerY,this.uniforms.mousePos=[this.mousePos.x,this.mousePos.y]},this.handleResize=()=>{this.setupCanvas()},this.handleContextLoss=()=>{this.stopAnimation()},this.handleContextRestored=()=>{this.setupWebGL().then(()=>{this.config.animation.enabled&&this.startAnimation()})},this.render=()=>{if(this.isDestroyed||!this.webglState)return;this.time+=.016*this.config.animation.speed,this.uniforms.time=this.time;const{gl:e}=this.webglState;e.clear(e.COLOR_BUFFER_BIT),this.updateUniforms(),e.drawArrays(e.TRIANGLE_STRIP,0,4),this.config.animation.enabled&&(this.animationId=requestAnimationFrame(this.render))},"string"==typeof e){const i=document.querySelector(e);if(!i)throw new n(`Canvas element not found: ${e}`,t.CANVAS_NOT_FOUND);this.canvas=i}else this.canvas=e;this.config={...a,...i},this.validateConfig(),this.uniforms={time:0,resolution:[this.canvas.width,this.canvas.height],mousePos:[this.config.mouse.centerX,this.config.mouse.centerY],refractionIndex:this.config.refractionIndex,dispersion:this.config.dispersion,thickness:this.config.thickness,glassSize:this.config.size,glassShape:this.getShapeIndex(this.config.shape),backgroundPattern:this.getPatternIndex(this.config.backgroundPattern)},this.init()}validateConfig(){if(this.config.size<=0||this.config.size>1)throw new n("Glass size must be between 0 and 1",t.INVALID_CONFIGURATION);if(this.config.refractionIndex<1||this.config.refractionIndex>3)throw new n("Refraction index must be between 1 and 3",t.INVALID_CONFIGURATION)}async init(){try{if(!i())throw new n("WebGL is not supported",t.WEBGL_NOT_SUPPORTED);await this.setupWebGL(),this.setupCanvas(),this.setupEventListeners(),this.config.animation.enabled&&this.startAnimation(),this.config.onReady()}catch(e){throw this.config.onError(e),e}}async setupWebGL(){const e=function(e){const i={antialias:!0,alpha:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!1,powerPreference:"default"};let r=e.getContext("webgl2",i);if(r||(r=e.getContext("webgl",i)),r||(r=e.getContext("experimental-webgl",i)),!r)throw new n("WebGL is not supported in this browser",t.WEBGL_NOT_SUPPORTED);return r}(this.canvas),i=function(e,i,r){const s=e.createProgram();if(!s)throw new n("Failed to create shader program",t.SHADER_COMPILATION_FAILED);if(e.attachShader(s,i),e.attachShader(s,r),e.linkProgram(s),!e.getProgramParameter(s,e.LINK_STATUS)){const i=e.getProgramInfoLog(s);throw e.deleteProgram(s),new n(`Program linking failed: ${i}`,t.SHADER_COMPILATION_FAILED)}return s}(e,r(e,e.VERTEX_SHADER,"\nattribute vec2 a_position;\nvarying vec2 v_uv;\n\nvoid main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n v_uv = (a_position + 1.0) * 0.5;\n}\n"),r(e,e.FRAGMENT_SHADER,"\nprecision highp float;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform vec2 u_mousePos;\nuniform float u_refractionIndex;\nuniform float u_dispersion;\nuniform float u_thickness;\nuniform float u_glassSize;\nuniform float u_glassShape;\nuniform float u_backgroundPattern;\nuniform sampler2D u_backgroundTexture;\n\nvarying vec2 v_uv;\n\n#define PI 3.14159265359\n\n// Noise function for surface perturbations\nfloat noise(vec2 p) {\n return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nfloat fbm(vec2 p) {\n float value = 0.0;\n float amplitude = 0.5;\n float frequency = 1.0;\n \n for(int i = 0; i < 4; i++) {\n value += amplitude * noise(p * frequency);\n amplitude *= 0.5;\n frequency *= 2.0;\n }\n return value;\n}\n\n// Ray-sphere intersection\nvec2 intersectSphere(vec3 rayOrigin, vec3 rayDir, vec3 sphereCenter, float radius) {\n vec3 oc = rayOrigin - sphereCenter;\n float b = dot(oc, rayDir);\n float c = dot(oc, oc) - radius * radius;\n float discriminant = b * b - c;\n \n if (discriminant < 0.0) return vec2(-1.0);\n \n float sqrt_discriminant = sqrt(discriminant);\n float t1 = -b - sqrt_discriminant;\n float t2 = -b + sqrt_discriminant;\n \n return vec2(t1, t2);\n}\n\n// Ray-cylinder intersection (infinite height)\nvec2 intersectCylinder(vec3 rayOrigin, vec3 rayDir, vec3 cylinderCenter, float radius) {\n vec2 ro = rayOrigin.xy - cylinderCenter.xy;\n vec2 rd = rayDir.xy;\n \n float a = dot(rd, rd);\n float b = 2.0 * dot(ro, rd);\n float c = dot(ro, ro) - radius * radius;\n \n float discriminant = b * b - 4.0 * a * c;\n if (discriminant < 0.0) return vec2(-1.0);\n \n float sqrt_discriminant = sqrt(discriminant);\n float t1 = (-b - sqrt_discriminant) / (2.0 * a);\n float t2 = (-b + sqrt_discriminant) / (2.0 * a);\n \n return vec2(t1, t2);\n}\n\n// Get sphere normal at point\nvec3 getSphereNormal(vec3 point, vec3 center) {\n return normalize(point - center);\n}\n\n// Get cylinder normal at point\nvec3 getCylinderNormal(vec3 point, vec3 center) {\n vec3 toPoint = point - center;\n return normalize(vec3(toPoint.xy, 0.0));\n}\n\n// 3D refraction using Snell's law\nvec3 refract3D(vec3 incident, vec3 normal, float eta) {\n float cosI = dot(-incident, normal);\n float sinT2 = eta * eta * (1.0 - cosI * cosI);\n \n if(sinT2 >= 1.0) {\n // Total internal reflection\n return reflect(incident, normal);\n }\n \n float cosT = sqrt(1.0 - sinT2);\n return eta * incident + (eta * cosI - cosT) * normal;\n}\n\n// Fresnel reflection coefficient\nfloat fresnel(float cosTheta, float n1, float n2) {\n float r0 = pow((n1 - n2) / (n1 + n2), 2.0);\n return r0 + (1.0 - r0) * pow(1.0 - cosTheta, 5.0);\n}\n\n// Generate different background patterns\nvec3 getBackgroundPattern(vec2 uv, float patternType) {\n if (patternType < 0.5) {\n // Black and white stripes\n float stripeWidth = 0.1;\n float stripe = step(0.5, mod(uv.x / stripeWidth, 1.0));\n return vec3(stripe);\n } else if (patternType < 1.5) {\n // Grid pattern\n float gridSize = 0.05;\n vec2 grid = step(0.5, mod(uv / gridSize, 1.0));\n float pattern = max(grid.x, grid.y);\n return vec3(pattern);\n } else if (patternType < 2.5) {\n // Concentric circles\n float dist = length(uv - 0.5);\n float rings = sin(dist * 50.0) * 0.5 + 0.5;\n return vec3(rings);\n } else {\n // Texture pattern - sample from background texture\n return texture2D(u_backgroundTexture, uv).rgb;\n }\n}\n\n// Ray trace through different glass shapes\nvec4 traceGlassShape(vec2 uv, vec2 mouseUV, float shapeType, float glassSize) {\n vec3 rayOrigin = vec3(uv, 2.0);\n vec3 rayDir = vec3(0.0, 0.0, -1.0);\n vec3 glassCenter = vec3(mouseUV, 0.0);\n \n vec2 intersections;\n vec3 normal1, normal2;\n vec3 enterPoint, exitPoint;\n \n // Different glass shapes\n if (shapeType < 0.5) {\n // Sphere\n intersections = intersectSphere(rayOrigin, rayDir, glassCenter, glassSize);\n if (intersections.x < 0.0) return vec4(0.0);\n \n enterPoint = rayOrigin + rayDir * intersections.x;\n exitPoint = rayOrigin + rayDir * intersections.y;\n normal1 = getSphereNormal(enterPoint, glassCenter);\n normal2 = -getSphereNormal(exitPoint, glassCenter);\n \n } else if (shapeType < 1.5) {\n // Cylinder\n intersections = intersectCylinder(rayOrigin, rayDir, glassCenter, glassSize);\n if (intersections.x < 0.0) return vec4(0.0);\n \n enterPoint = rayOrigin + rayDir * intersections.x;\n exitPoint = rayOrigin + rayDir * intersections.y;\n normal1 = getCylinderNormal(enterPoint, glassCenter);\n normal2 = -getCylinderNormal(exitPoint, glassCenter);\n \n } else if (shapeType < 2.5) {\n // Convex lens (approximated as flattened sphere)\n float lensRatio = 1.5;\n vec3 lensCenter = vec3(mouseUV, 0.0);\n intersections = intersectSphere(rayOrigin, rayDir, lensCenter, glassSize * lensRatio);\n if (intersections.x < 0.0) return vec4(0.0);\n \n enterPoint = rayOrigin + rayDir * intersections.x;\n exitPoint = rayOrigin + rayDir * intersections.y;\n normal1 = getSphereNormal(enterPoint, lensCenter);\n normal2 = -getSphereNormal(exitPoint, lensCenter);\n \n // Flatten the lens effect\n normal1.z *= 0.3;\n normal2.z *= 0.3;\n normal1 = normalize(normal1);\n normal2 = normalize(normal2);\n \n } else if (shapeType < 3.5) {\n // Triangular prism (simplified)\n float dist = length(uv - mouseUV);\n if (dist > glassSize) return vec4(0.0);\n \n // Create triangular shape effect\n vec2 centered = uv - mouseUV;\n float angle = atan(centered.y, centered.x);\n float prismEffect = sin(angle * 3.0) * 0.3 + 0.7;\n \n if (dist > glassSize * prismEffect) return vec4(0.0);\n \n // Simplified prism normals\n normal1 = normalize(vec3(sin(angle * 3.0), cos(angle * 3.0), 1.0));\n normal2 = -normal1;\n \n } else {\n // Flat glass\n float dist = length(uv - mouseUV);\n if (dist > glassSize) return vec4(0.0);\n \n normal1 = vec3(0.0, 0.0, 1.0);\n normal2 = vec3(0.0, 0.0, -1.0);\n }\n \n // Add surface perturbations\n vec3 perturbation = vec3(\n fbm(uv * 20.0 + u_time * 0.1) * 0.02,\n fbm(uv * 20.0 + u_time * 0.13) * 0.02,\n 0.0\n );\n normal1 = normalize(normal1 + perturbation);\n normal2 = normalize(normal2 + perturbation);\n \n return vec4(normal1, 1.0); // Return first normal for now\n}\n\nvoid main() {\n vec2 uv = v_uv;\n vec2 mouseUV = u_mousePos;\n \n vec4 glassInfo = traceGlassShape(uv, mouseUV, u_glassShape, u_glassSize);\n \n if (glassInfo.w < 0.5) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n return;\n }\n \n vec3 normal = glassInfo.xyz;\n \n // Calculate view direction\n vec3 viewDir = vec3(0.0, 0.0, 1.0);\n float cosTheta = abs(dot(viewDir, normal));\n \n // Fresnel effect\n float fresnelTerm = fresnel(cosTheta, 1.0, u_refractionIndex);\n \n // Chromatic dispersion - different wavelengths refract differently\n float redEta = 1.0 / (u_refractionIndex - u_dispersion);\n float greenEta = 1.0 / u_refractionIndex;\n float blueEta = 1.0 / (u_refractionIndex + u_dispersion);\n \n // Calculate refracted rays for each color channel\n vec3 refractedR = refract3D(-viewDir, normal, redEta);\n vec3 refractedG = refract3D(-viewDir, normal, greenEta);\n vec3 refractedB = refract3D(-viewDir, normal, blueEta);\n \n // Calculate distortion based on glass geometry and thickness\n float distortionScale = u_thickness * 0.3;\n \n // For sphere and lens, create strong curvature distortion\n if (u_glassShape < 2.5) {\n vec2 centerOffset = uv - mouseUV;\n float distFromCenter = length(centerOffset);\n float curvatureEffect = 1.0 + distFromCenter * distFromCenter * 2.0;\n distortionScale *= curvatureEffect;\n }\n \n vec2 offsetR = refractedR.xy * distortionScale;\n vec2 offsetG = refractedG.xy * distortionScale;\n vec2 offsetB = refractedB.xy * distortionScale;\n \n // Sample background with strong geometric distortion\n vec3 bgColorR = getBackgroundPattern(uv + offsetR, u_backgroundPattern);\n vec3 bgColorG = getBackgroundPattern(uv + offsetG, u_backgroundPattern);\n vec3 bgColorB = getBackgroundPattern(uv + offsetB, u_backgroundPattern);\n \n vec3 refractedColor = vec3(bgColorR.r, bgColorG.g, bgColorB.b);\n \n // Reflection color\n vec3 reflectionColor = vec3(0.9, 0.95, 1.0);\n \n // Combine reflection and refraction\n vec3 finalColor = mix(refractedColor, reflectionColor, fresnelTerm);\n \n // Add caustic effects\n float caustic = pow(max(0.0, dot(normal, vec3(0.5, 0.5, 1.0))), 3.0);\n finalColor += caustic * 0.4 * vec3(1.0, 1.0, 0.9);\n \n // Glass transparency\n float dist = length(uv - mouseUV);\n float glassMask = smoothstep(u_glassSize + 0.02, u_glassSize - 0.02, dist);\n \n // Make glass more transparent to show background properly\n float alpha = glassMask * 0.4;\n \n // Edge enhancement for glass rim effect\n float edge = 1.0 - smoothstep(u_glassSize - 0.005, u_glassSize, dist);\n alpha += edge * 0.6;\n \n // Ensure the glass effect blends properly with background\n gl_FragColor = vec4(finalColor, alpha);\n}\n"));e.useProgram(i);const a=function(e,n,t){const i={};for(const r of t)i[r]=e.getUniformLocation(n,r);return i}(e,i,["u_time","u_resolution","u_mousePos","u_refractionIndex","u_dispersion","u_thickness","u_glassSize","u_glassShape","u_backgroundPattern","u_backgroundTexture"]);this.vertexBuffer=function(e){const i=new Float32Array([-1,-1,1,-1,-1,1,1,1]),r=e.createBuffer();if(!r)throw new n("Failed to create vertex buffer",t.WEBGL_NOT_SUPPORTED);return e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,i,e.STATIC_DRAW),r}(e);const c=e.getAttribLocation(i,"a_position");let l;e.enableVertexAttribArray(c),e.vertexAttribPointer(c,2,e.FLOAT,!1,0,0),l=this.config.backgroundTexture?"string"==typeof this.config.backgroundTexture?await o(e,this.config.backgroundTexture):s(e,this.config.backgroundTexture):function(e){const n=document.createElement("canvas"),t=n.getContext("2d");n.width=256,n.height=256;const i=t.createLinearGradient(0,0,256,256);return i.addColorStop(0,"#2d4a3d"),i.addColorStop(.5,"#4a7c59"),i.addColorStop(1,"#6ba368"),t.fillStyle=i,t.fillRect(0,0,256,256),s(e,n)}(e),e.viewport(0,0,this.canvas.width,this.canvas.height),e.clearColor(0,0,0,0),e.enable(e.BLEND),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA),this.webglState={gl:e,program:i,uniformLocations:a,backgroundTexture:l}}setupCanvas(){const{pixelRatio:e}=this.config.performance,n=this.canvas.getBoundingClientRect();this.canvas.width=n.width*e,this.canvas.height=n.height*e,this.canvas.style.width=n.width+"px",this.canvas.style.height=n.height+"px",this.uniforms.resolution=[this.canvas.width,this.canvas.height],this.webglState&&this.webglState.gl.viewport(0,0,this.canvas.width,this.canvas.height)}setupEventListeners(){this.config.mouse.enabled&&this.config.mouse.followCursor&&(this.canvas.addEventListener("mousemove",this.handleMouseMove),this.canvas.addEventListener("mouseleave",this.handleMouseLeave)),window.addEventListener("resize",this.handleResize),this.cleanupContextLoss=function(e,n,t){const i=e=>{e.preventDefault(),n()},r=()=>{t()};return e.addEventListener("webglcontextlost",i,!1),e.addEventListener("webglcontextrestored",r,!1),()=>{e.removeEventListener("webglcontextlost",i),e.removeEventListener("webglcontextrestored",r)}}(this.canvas,this.handleContextLoss,this.handleContextRestored)}getShapeIndex(e){return["sphere","cylinder","lens","prism","flat"].indexOf(e)}getPatternIndex(e){return["stripes","grid","circles","texture"].indexOf(e)}updateUniforms(){if(!this.webglState)return;const{gl:e,uniformLocations:n}=this.webglState;e.uniform1f(n.u_time,this.uniforms.time),e.uniform2f(n.u_resolution,...this.uniforms.resolution),e.uniform2f(n.u_mousePos,...this.uniforms.mousePos),e.uniform1f(n.u_refractionIndex,this.uniforms.refractionIndex),e.uniform1f(n.u_dispersion,this.uniforms.dispersion),e.uniform1f(n.u_thickness,this.uniforms.thickness),e.uniform1f(n.u_glassSize,this.uniforms.glassSize),e.uniform1f(n.u_glassShape,this.uniforms.glassShape),e.uniform1f(n.u_backgroundPattern,this.uniforms.backgroundPattern),this.webglState.backgroundTexture&&(e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,this.webglState.backgroundTexture),e.uniform1i(n.u_backgroundTexture,0))}setShape(e){this.config.shape=e,this.uniforms.glassShape=this.getShapeIndex(e),this.config.onShapeChange(e)}setSize(e){this.config.size=Math.max(.01,Math.min(1,e)),this.uniforms.glassSize=this.config.size}setRefractionIndex(e){this.config.refractionIndex=Math.max(1,Math.min(3,e)),this.uniforms.refractionIndex=this.config.refractionIndex}setDispersion(e){this.config.dispersion=Math.max(0,Math.min(.2,e)),this.uniforms.dispersion=this.config.dispersion}setThickness(e){this.config.thickness=Math.max(.1,Math.min(2,e)),this.uniforms.thickness=this.config.thickness}setBackgroundPattern(e){this.config.backgroundPattern=e,this.uniforms.backgroundPattern=this.getPatternIndex(e)}async setBackgroundTexture(e){if(this.webglState)try{let n;n="string"==typeof e?await o(this.webglState.gl,e):s(this.webglState.gl,e),this.webglState.backgroundTexture&&this.webglState.gl.deleteTexture(this.webglState.backgroundTexture),this.webglState.backgroundTexture=n,this.config.backgroundTexture=e}catch(e){this.config.onError(e)}}setMaterial(n){const t="string"==typeof n?e[n]:n;t&&(this.setRefractionIndex(t.refractionIndex),this.setDispersion(t.dispersion),this.config.onMaterialChange(t))}getMaterials(){return Object.values(e)}setMousePosition(e,n){this.mousePos.x=Math.max(0,Math.min(1,e)),this.mousePos.y=Math.max(0,Math.min(1,n)),this.uniforms.mousePos=[this.mousePos.x,this.mousePos.y]}enableMouseTracking(e){this.config.mouse.enabled=e,e||this.setMousePosition(this.config.mouse.centerX,this.config.mouse.centerY)}startAnimation(){this.config.animation.enabled=!0,this.animationId||this.render()}stopAnimation(){this.config.animation.enabled=!1,this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}setAnimationSpeed(e){this.config.animation.speed=Math.max(0,Math.min(5,e))}resize(){this.handleResize()}destroy(){if(this.isDestroyed=!0,this.stopAnimation(),this.canvas.removeEventListener("mousemove",this.handleMouseMove),this.canvas.removeEventListener("mouseleave",this.handleMouseLeave),window.removeEventListener("resize",this.handleResize),this.cleanupContextLoss&&this.cleanupContextLoss(),this.webglState){const{gl:e}=this.webglState;this.webglState.backgroundTexture&&e.deleteTexture(this.webglState.backgroundTexture),this.vertexBuffer&&e.deleteBuffer(this.vertexBuffer),this.webglState.program&&e.deleteProgram(this.webglState.program)}this.webglState=null}getConfig(){return{...this.config}}getCanvas(){return this.canvas}isWebGLSupported(){return i()}}exports.ERROR_CODES=t,exports.GLASS_MATERIALS=e,exports.PhysicsGlass=c,exports.PhysicsGlassError=n,exports.default=c,exports.isWebGLSupported=i; //# sourceMappingURL=index.js.map