@leeguoo/pwtk-network-debugger 1.3.0 → 1.3.1-beta.1

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/README.md CHANGED
@@ -16,16 +16,29 @@
16
16
 
17
17
  ## 📦 安装
18
18
 
19
+ ### npm 安装
20
+
19
21
  ```bash
20
- npm install @leeguoo/network-debugger
22
+ npm install @leeguoo/pwtk-network-debugger
21
23
  ```
22
24
 
23
- 或使用 CDN:
25
+ ### CDN 引入
26
+
27
+ **推荐使用精确版本号,避免缓存问题:**
24
28
 
25
29
  ```html
26
- <script src="https://unpkg.com/@leeguoo/network-debugger/dist/index.js"></script>
30
+ <!-- 推荐:使用精确版本号 -->
31
+ <script src="https://cdn.jsdelivr.net/npm/@leeguoo/pwtk-network-debugger@1.3.0/dist/index.js"></script>
32
+
33
+ <!-- 或使用 unpkg -->
34
+ <script src="https://unpkg.com/@leeguoo/pwtk-network-debugger@1.3.0/dist/index.js"></script>
27
35
  ```
28
36
 
37
+ **注意**: 如果使用 `@latest` 标签,可能由于 CDN 缓存导致加载到旧版本。建议:
38
+ 1. 使用具体版本号
39
+ 2. 添加时间戳参数:`?t=${Date.now()}`
40
+ 3. 查看最新版本:[npm 主页](https://www.npmjs.com/package/@leeguoo/pwtk-network-debugger)
41
+
29
42
  ## 🚀 快速开始
30
43
 
31
44
  ### ESM/TypeScript 项目
@@ -70,10 +83,12 @@ NetworkDebugger.init({
70
83
  <body>
71
84
  <!-- 您的页面内容 -->
72
85
 
73
- <script src="https://unpkg.com/@leeguoo/network-debugger/dist/index.js"></script>
86
+ <!-- 推荐:使用精确版本号避免缓存 -->
87
+ <script src="https://cdn.jsdelivr.net/npm/@leeguoo/pwtk-network-debugger@1.3.0/dist/index.js"></script>
74
88
  <script>
75
89
  // 等待页面加载完成
76
90
  window.addEventListener('DOMContentLoaded', async () => {
91
+ const NetworkDebugger = window.NetworkDebugger?.default || window.NetworkDebugger;
77
92
  await NetworkDebugger.init({
78
93
  position: 'bottom-right',
79
94
  minimized: false
@@ -84,6 +99,42 @@ NetworkDebugger.init({
84
99
  </html>
85
100
  ```
86
101
 
102
+ ### 控制台一键安装(推荐用于临时调试)
103
+
104
+ 在任何网站的开发者控制台中运行:
105
+
106
+ ```javascript
107
+ (function(){
108
+ 'use strict';
109
+ const VERSION='1.3.0';
110
+ const CDN_URLS=[
111
+ 'https://cdn.jsdelivr.net/npm/@leeguoo/pwtk-network-debugger@'+VERSION+'/dist/index.js',
112
+ 'https://unpkg.com/@leeguoo/pwtk-network-debugger@'+VERSION+'/dist/index.js'
113
+ ];
114
+ let idx=0;
115
+ function load(){
116
+ if(idx>=CDN_URLS.length){
117
+ console.error('[PWTK] 所有 CDN 都失败');
118
+ return;
119
+ }
120
+ const s=document.createElement('script');
121
+ s.src=CDN_URLS[idx];
122
+ s.crossOrigin='anonymous';
123
+ s.onload=async()=>{
124
+ await new Promise(r=>setTimeout(r,500));
125
+ const nd=window.NetworkDebugger?.default||window.NetworkDebugger;
126
+ if(nd){
127
+ await nd.init({position:'bottom-right',decrypt:{enabled:true}});
128
+ console.log('✅ PWTK 解密工具已加载!');
129
+ }
130
+ };
131
+ s.onerror=()=>{idx++;load();};
132
+ document.head.appendChild(s);
133
+ }
134
+ load();
135
+ })();
136
+ ```
137
+
87
138
  ## ⚙️ 配置选项
88
139
 
89
140
  ```typescript
@@ -253,6 +304,76 @@ const wasmLoaded = debugger.isWasmLoaded()
253
304
  - 所有网络请求的拦截和解密都在浏览器内完成
254
305
  - 可以完全离线使用
255
306
 
307
+ ## 🔧 故障排除
308
+
309
+ ### 问题:加载的是旧版本
310
+
311
+ **症状**: 安装后,功能没有更新,控制台显示的版本号是旧的。
312
+
313
+ **原因**: CDN 缓存导致。jsDelivr 和 unpkg 会缓存 `@latest` 标签,缓存时间可能长达 12-24 小时。
314
+
315
+ **解决方案**:
316
+
317
+ 1. **使用精确版本号(强烈推荐)**:
318
+ ```html
319
+ <!-- 替换 @latest 为具体版本号 -->
320
+ <script src="https://cdn.jsdelivr.net/npm/@leeguoo/pwtk-network-debugger@1.3.0/dist/index.js"></script>
321
+ ```
322
+
323
+ 2. **添加缓存破坏参数**:
324
+ ```html
325
+ <script src="https://cdn.jsdelivr.net/npm/@leeguoo/pwtk-network-debugger@latest/dist/index.js?t=1234567890"></script>
326
+ ```
327
+
328
+ 3. **硬刷新浏览器**:
329
+ - Windows/Linux: `Ctrl + Shift + R` 或 `Ctrl + F5`
330
+ - Mac: `Cmd + Shift + R`
331
+
332
+ 4. **清除浏览器缓存**:
333
+ - 打开开发者工具 (F12)
334
+ - 右键点击刷新按钮
335
+ - 选择"清空缓存并硬性重新加载"
336
+
337
+ 5. **手动清除 jsDelivr 缓存**:
338
+ ```bash
339
+ curl -X PURGE https://cdn.jsdelivr.net/npm/@leeguoo/pwtk-network-debugger@latest/dist/index.js
340
+ ```
341
+
342
+ ### 问题:面板不显示
343
+
344
+ **可能原因**:
345
+ 1. 脚本加载失败(检查控制台错误)
346
+ 2. CSP(内容安全策略)限制
347
+ 3. 其他脚本冲突
348
+
349
+ **解决方案**:
350
+ 1. 检查浏览器控制台是否有错误信息
351
+ 2. 尝试使用不同的 CDN
352
+ 3. 确保在 `DOMContentLoaded` 之后初始化
353
+
354
+ ### 问题:解密功能不工作
355
+
356
+ **可能原因**:
357
+ 1. WebAssembly 文件未正确加载
358
+ 2. 密钥提取器配置不正确
359
+
360
+ **解决方案**:
361
+ 1. 检查 `wasmUrl` 配置是否正确
362
+ 2. 验证 `keyExtractor` 和 `slkExtractor` 函数
363
+ 3. 查看控制台日志了解详细错误
364
+
365
+ ### 查看当前版本
366
+
367
+ 在控制台中运行:
368
+ ```javascript
369
+ console.log(window.NetworkDebugger?.version || 'Unknown');
370
+ ```
371
+
372
+ 或查看成功加载的日志:
373
+ ```
374
+ ✅ PWTK 解密工具 v1.3.0 已成功加载!
375
+ ```
376
+
256
377
  ## 🤝 贡献
257
378
 
258
379
  欢迎提交 Issue 和 Pull Request!
@@ -0,0 +1 @@
1
+ "use strict";class e{static instances=[];static pageSnapshot=null;static isCapturing=!1;static waitingForSnapshot=[];constructor(t={}){this.width=0;this.height=0;this.borderRadius=t.borderRadius||48;this.type=t.type||"rounded";this.tintOpacity=void 0!==t.tintOpacity?t.tintOpacity:.2;this.canvas=null;this.element=null;this.gl=null;this.gl_refs={};this.webglInitialized=!1;this.children=[];e.instances.push(this);this.init()}addChild(e){this.children.push(e);e.parent=this;if(e.element&&this.element)this.element.appendChild(e.element);if(e instanceof Button)e.setupAsNestedGlass();this.updateSizeFromDOM();return e}removeChild(e){const t=this.children.indexOf(e);if(t>-1){this.children.splice(t,1);e.parent=null;if(e.element&&this.element.contains(e.element))this.element.removeChild(e.element);this.updateSizeFromDOM()}}updateSizeFromDOM(){requestAnimationFrame(()=>{const e=this.element.getBoundingClientRect();let t=Math.ceil(e.width),n=Math.ceil(e.height);if("circle"===this.type){const e=Math.max(t,n);t=e;n=e;this.borderRadius=e/2;this.element.style.width=e+"px";this.element.style.height=e+"px";this.element.style.borderRadius=this.borderRadius+"px"}else if("pill"===this.type){this.borderRadius=n/2;this.element.style.borderRadius=this.borderRadius+"px"}if(t!==this.width||n!==this.height){this.width=t;this.height=n;this.canvas.width=t;this.canvas.height=n;this.canvas.style.width=t+"px";this.canvas.style.height=n+"px";this.canvas.style.borderRadius=this.borderRadius+"px";if(this.gl_refs.gl){this.gl_refs.gl.viewport(0,0,t,n);this.gl_refs.gl.uniform2f(this.gl_refs.resolutionLoc,t,n);this.gl_refs.gl.uniform1f(this.gl_refs.borderRadiusLoc,this.borderRadius)}this.children.forEach(e=>{if(e instanceof Button&&e.isNestedGlass&&e.gl_refs.gl){const i=e.gl_refs.gl;i.bindTexture(i.TEXTURE_2D,e.gl_refs.texture);i.texImage2D(i.TEXTURE_2D,0,i.RGBA,t,n,0,i.RGBA,i.UNSIGNED_BYTE,null);i.uniform2f(e.gl_refs.textureSizeLoc,t,n);if(e.gl_refs.containerSizeLoc)i.uniform2f(e.gl_refs.containerSizeLoc,t,n)}})}})}init(){this.createElement();this.setupCanvas();this.updateSizeFromDOM();if(e.pageSnapshot)this.initWebGL();else if(e.isCapturing)e.waitingForSnapshot.push(this);else{e.isCapturing=!0;e.waitingForSnapshot.push(this);this.capturePageSnapshot()}}createElement(){this.element=document.createElement("div");this.element.className="glass-container";if("circle"===this.type)this.element.classList.add("glass-container-circle");else if("pill"===this.type)this.element.classList.add("glass-container-pill");this.element.style.borderRadius=this.borderRadius+"px";this.canvas=document.createElement("canvas");this.canvas.style.borderRadius=this.borderRadius+"px";this.canvas.style.position="absolute";this.canvas.style.top="0";this.canvas.style.left="0";this.canvas.style.width="100%";this.canvas.style.height="100%";this.canvas.style.boxShadow="0 25px 50px rgba(0, 0, 0, 0.25)";this.canvas.style.zIndex="-1";this.element.appendChild(this.canvas)}setupCanvas(){this.gl=this.canvas.getContext("webgl",{preserveDrawingBuffer:!0});if(this.gl);else console.error("WebGL not supported")}getPosition(){const e=this.canvas.getBoundingClientRect();return{x:e.left+e.width/2,y:e.top+e.height/2}}capturePageSnapshot(){console.log("Capturing page snapshot...");const t=window.html2canvas;if(t)t(document.body,{scale:1,useCORS:!0,allowTaint:!0,backgroundColor:null,ignoreElements:function(e){return e.classList.contains("glass-container")||e.classList.contains("glass-button")||e.classList.contains("glass-button-text")}}).then(t=>{console.log("Page snapshot captured");e.pageSnapshot=t;e.isCapturing=!1;const n=e.waitingForSnapshot.slice();e.waitingForSnapshot=[];n.forEach(e=>{if(!e.webglInitialized)e.initWebGL()})}).catch(t=>{console.error("[PWTK] html2canvas error:",t);e.isCapturing=!1;e.waitingForSnapshot=[]});else{console.error("[PWTK] html2canvas not available, containers will not initialize");e.isCapturing=!1;e.waitingForSnapshot=[]}}initWebGL(){if(!e.pageSnapshot||!this.gl)return;const t=new Image;t.src=e.pageSnapshot.toDataURL();t.onload=()=>{this.setupShader(t);this.webglInitialized=!0}}setupShader(e){const t=this.gl,n=this.createProgram(t,"\n attribute vec2 a_position;\n attribute vec2 a_texcoord;\n varying vec2 v_texcoord;\n\n void main() {\n gl_Position = vec4(a_position, 0, 1);\n v_texcoord = a_texcoord;\n }\n ","\n precision mediump float;\n uniform sampler2D u_image;\n uniform vec2 u_resolution;\n uniform vec2 u_textureSize;\n uniform float u_scrollY;\n uniform float u_pageHeight;\n uniform float u_viewportHeight;\n uniform float u_blurRadius;\n uniform float u_borderRadius;\n uniform vec2 u_containerPosition;\n uniform float u_warp;\n uniform float u_edgeIntensity;\n uniform float u_rimIntensity;\n uniform float u_baseIntensity;\n uniform float u_edgeDistance;\n uniform float u_rimDistance;\n uniform float u_baseDistance;\n uniform float u_cornerBoost;\n uniform float u_rippleEffect;\n uniform float u_tintOpacity;\n varying vec2 v_texcoord;\n\n // Function to calculate distance from rounded rectangle edge\n float roundedRectDistance(vec2 coord, vec2 size, float radius) {\n vec2 center = size * 0.5;\n vec2 pixelCoord = coord * size;\n vec2 toCorner = abs(pixelCoord - center) - (center - radius);\n float outsideCorner = length(max(toCorner, 0.0));\n float insideCorner = min(max(toCorner.x, toCorner.y), 0.0);\n return (outsideCorner + insideCorner - radius);\n }\n \n // Function to calculate distance from circle edge (negative inside, positive outside)\n float circleDistance(vec2 coord, vec2 size, float radius) {\n vec2 center = vec2(0.5, 0.5);\n vec2 pixelCoord = coord * size;\n vec2 centerPixel = center * size;\n float distFromCenter = length(pixelCoord - centerPixel);\n return distFromCenter - radius;\n }\n \n // Check if this is a pill (border radius is approximately 50% of height AND width > height)\n bool isPill(vec2 size, float radius) {\n float heightRatioDiff = abs(radius - size.y * 0.5);\n bool radiusMatchesHeight = heightRatioDiff < 2.0;\n bool isWiderThanTall = size.x > size.y + 4.0; // Must be significantly wider\n return radiusMatchesHeight && isWiderThanTall;\n }\n \n // Check if this is a circle (border radius is approximately 50% of smaller dimension AND roughly square)\n bool isCircle(vec2 size, float radius) {\n float minDim = min(size.x, size.y);\n bool radiusMatchesMinDim = abs(radius - minDim * 0.5) < 1.0;\n bool isRoughlySquare = abs(size.x - size.y) < 4.0; // Width and height are similar\n return radiusMatchesMinDim && isRoughlySquare;\n }\n \n // Function to calculate distance from pill edge (capsule shape)\n float pillDistance(vec2 coord, vec2 size, float radius) {\n vec2 center = size * 0.5;\n vec2 pixelCoord = coord * size;\n \n // Proper capsule: line segment with radius\n // The capsule axis runs horizontally from (radius, center.y) to (size.x - radius, center.y)\n vec2 capsuleStart = vec2(radius, center.y);\n vec2 capsuleEnd = vec2(size.x - radius, center.y);\n \n // Project point onto the capsule axis (line segment)\n vec2 capsuleAxis = capsuleEnd - capsuleStart;\n float capsuleLength = length(capsuleAxis);\n \n if (capsuleLength > 0.0) {\n vec2 toPoint = pixelCoord - capsuleStart;\n float t = clamp(dot(toPoint, capsuleAxis) / dot(capsuleAxis, capsuleAxis), 0.0, 1.0);\n vec2 closestPointOnAxis = capsuleStart + t * capsuleAxis;\n return length(pixelCoord - closestPointOnAxis) - radius;\n } else {\n // Degenerate case: just a circle\n return length(pixelCoord - center) - radius;\n }\n }\n\n void main() {\n vec2 coord = v_texcoord;\n \n // Calculate which area of the page should be visible through the container\n float scrollY = u_scrollY;\n vec2 containerSize = u_resolution;\n vec2 textureSize = u_textureSize;\n \n // Container position in viewport coordinates\n vec2 containerCenter = u_containerPosition + vec2(0.0, scrollY);\n \n // Convert container coordinates to page coordinates\n vec2 containerOffset = (coord - 0.5) * containerSize;\n vec2 pagePixel = containerCenter + containerOffset;\n \n // Convert to texture coordinate (0 to 1)\n vec2 textureCoord = pagePixel / textureSize;\n \n // Glass refraction effects\n float distFromEdgeShape;\n vec2 shapeNormal; // Normal vector pointing away from shape surface\n \n if (isPill(u_resolution, u_borderRadius)) {\n distFromEdgeShape = -pillDistance(coord, u_resolution, u_borderRadius);\n \n // Calculate normal for pill shape\n vec2 center = vec2(0.5, 0.5);\n vec2 pixelCoord = coord * u_resolution;\n vec2 capsuleStart = vec2(u_borderRadius, center.y * u_resolution.y);\n vec2 capsuleEnd = vec2(u_resolution.x - u_borderRadius, center.y * u_resolution.y);\n vec2 capsuleAxis = capsuleEnd - capsuleStart;\n float capsuleLength = length(capsuleAxis);\n \n if (capsuleLength > 0.0) {\n vec2 toPoint = pixelCoord - capsuleStart;\n float t = clamp(dot(toPoint, capsuleAxis) / dot(capsuleAxis, capsuleAxis), 0.0, 1.0);\n vec2 closestPointOnAxis = capsuleStart + t * capsuleAxis;\n vec2 normalDir = pixelCoord - closestPointOnAxis;\n shapeNormal = length(normalDir) > 0.0 ? normalize(normalDir) : vec2(0.0, 1.0);\n } else {\n shapeNormal = normalize(coord - center);\n }\n } else if (isCircle(u_resolution, u_borderRadius)) {\n distFromEdgeShape = -circleDistance(coord, u_resolution, u_borderRadius);\n vec2 center = vec2(0.5, 0.5);\n shapeNormal = normalize(coord - center);\n } else {\n distFromEdgeShape = -roundedRectDistance(coord, u_resolution, u_borderRadius);\n vec2 center = vec2(0.5, 0.5);\n shapeNormal = normalize(coord - center);\n }\n distFromEdgeShape = max(distFromEdgeShape, 0.0);\n \n float distFromLeft = coord.x;\n float distFromRight = 1.0 - coord.x;\n float distFromTop = coord.y;\n float distFromBottom = 1.0 - coord.y;\n float distFromEdge = distFromEdgeShape / min(u_resolution.x, u_resolution.y);\n \n // Smooth glass refraction using shape-aware normal\n float normalizedDistance = distFromEdge * min(u_resolution.x, u_resolution.y);\n float baseIntensity = 1.0 - exp(-normalizedDistance * u_baseDistance);\n float edgeIntensity = exp(-normalizedDistance * u_edgeDistance);\n float rimIntensity = exp(-normalizedDistance * u_rimDistance);\n \n // Apply center warping only if warp is enabled, keep edge and rim effects always\n float baseComponent = u_warp > 0.5 ? baseIntensity * u_baseIntensity : 0.0;\n float totalIntensity = baseComponent + edgeIntensity * u_edgeIntensity + rimIntensity * u_rimIntensity;\n \n vec2 baseRefraction = shapeNormal * totalIntensity;\n \n float cornerProximityX = min(distFromLeft, distFromRight);\n float cornerProximityY = min(distFromTop, distFromBottom);\n float cornerDistance = max(cornerProximityX, cornerProximityY);\n float cornerNormalized = cornerDistance * min(u_resolution.x, u_resolution.y);\n \n float cornerBoost = exp(-cornerNormalized * 0.3) * u_cornerBoost;\n vec2 cornerRefraction = shapeNormal * cornerBoost;\n \n vec2 perpendicular = vec2(-shapeNormal.y, shapeNormal.x);\n float rippleEffect = sin(distFromEdge * 25.0) * u_rippleEffect * rimIntensity;\n vec2 textureRefraction = perpendicular * rippleEffect;\n \n vec2 totalRefraction = baseRefraction + cornerRefraction + textureRefraction;\n textureCoord += totalRefraction;\n \n // Gaussian blur\n vec4 color = vec4(0.0);\n vec2 texelSize = 1.0 / u_textureSize;\n float sigma = u_blurRadius / 2.0;\n vec2 blurStep = texelSize * sigma;\n \n float totalWeight = 0.0;\n \n for(float i = -6.0; i <= 6.0; i += 1.0) {\n for(float j = -6.0; j <= 6.0; j += 1.0) {\n float distance = length(vec2(i, j));\n if(distance > 6.0) continue;\n \n float weight = exp(-(distance * distance) / (2.0 * sigma * sigma));\n \n vec2 offset = vec2(i, j) * blurStep;\n color += texture2D(u_image, textureCoord + offset) * weight;\n totalWeight += weight;\n }\n }\n \n color /= totalWeight;\n \n // Simple vertical gradient\n float gradientPosition = coord.y;\n vec3 topTint = vec3(1.0, 1.0, 1.0);\n vec3 bottomTint = vec3(0.7, 0.7, 0.7);\n vec3 gradientTint = mix(topTint, bottomTint, gradientPosition);\n vec3 tintedColor = mix(color.rgb, gradientTint, u_tintOpacity);\n color = vec4(tintedColor, color.a);\n \n // Sampled gradient\n vec2 viewportCenter = containerCenter;\n float topY = (viewportCenter.y - containerSize.y * 0.4) / textureSize.y;\n float midY = viewportCenter.y / textureSize.y;\n float bottomY = (viewportCenter.y + containerSize.y * 0.4) / textureSize.y;\n \n vec3 topColor = vec3(0.0);\n vec3 midColor = vec3(0.0);\n vec3 bottomColor = vec3(0.0);\n \n float sampleCount = 0.0;\n for(float x = 0.0; x < 1.0; x += 0.05) {\n for(float yOffset = -5.0; yOffset <= 5.0; yOffset += 1.0) {\n vec2 topSample = vec2(x, topY + yOffset * texelSize.y);\n vec2 midSample = vec2(x, midY + yOffset * texelSize.y);\n vec2 bottomSample = vec2(x, bottomY + yOffset * texelSize.y);\n \n topColor += texture2D(u_image, topSample).rgb;\n midColor += texture2D(u_image, midSample).rgb;\n bottomColor += texture2D(u_image, bottomSample).rgb;\n sampleCount += 1.0;\n }\n }\n \n topColor /= sampleCount;\n midColor /= sampleCount;\n bottomColor /= sampleCount;\n \n vec3 sampledGradient;\n if (gradientPosition < 0.1) {\n sampledGradient = topColor;\n } else if (gradientPosition > 0.9) {\n sampledGradient = bottomColor;\n } else {\n float transitionPos = (gradientPosition - 0.1) / 0.8;\n if (transitionPos < 0.5) {\n float t = transitionPos * 2.0;\n sampledGradient = mix(topColor, midColor, t);\n } else {\n float t = (transitionPos - 0.5) * 2.0;\n sampledGradient = mix(midColor, bottomColor, t);\n }\n }\n \n vec3 finalTinted = mix(color.rgb, sampledGradient, u_tintOpacity * 0.3);\n color = vec4(finalTinted, color.a);\n \n // Shape mask (rounded rectangle, circle, or pill)\n float maskDistance;\n if (isPill(u_resolution, u_borderRadius)) {\n maskDistance = pillDistance(coord, u_resolution, u_borderRadius);\n } else if (isCircle(u_resolution, u_borderRadius)) {\n maskDistance = circleDistance(coord, u_resolution, u_borderRadius);\n } else {\n maskDistance = roundedRectDistance(coord, u_resolution, u_borderRadius);\n }\n float mask = 1.0 - smoothstep(-1.0, 1.0, maskDistance);\n \n gl_FragColor = vec4(color.rgb, mask);\n }\n ");if(!n)return;t.useProgram(n);const i=t.createBuffer();t.bindBuffer(t.ARRAY_BUFFER,i);t.bufferData(t.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),t.STATIC_DRAW);const o=t.createBuffer();t.bindBuffer(t.ARRAY_BUFFER,o);t.bufferData(t.ARRAY_BUFFER,new Float32Array([0,1,1,1,0,0,0,0,1,1,1,0]),t.STATIC_DRAW);const r=t.getAttribLocation(n,"a_position"),s=t.getAttribLocation(n,"a_texcoord"),a=t.getUniformLocation(n,"u_resolution"),l=t.getUniformLocation(n,"u_textureSize"),c=t.getUniformLocation(n,"u_scrollY"),u=t.getUniformLocation(n,"u_pageHeight"),d=t.getUniformLocation(n,"u_viewportHeight"),f=t.getUniformLocation(n,"u_blurRadius"),m=t.getUniformLocation(n,"u_borderRadius"),h=t.getUniformLocation(n,"u_containerPosition"),p=t.getUniformLocation(n,"u_warp"),g=t.getUniformLocation(n,"u_edgeIntensity"),v=t.getUniformLocation(n,"u_rimIntensity"),_=t.getUniformLocation(n,"u_baseIntensity"),x=t.getUniformLocation(n,"u_edgeDistance"),b=t.getUniformLocation(n,"u_rimDistance"),y=t.getUniformLocation(n,"u_baseDistance"),R=t.getUniformLocation(n,"u_cornerBoost"),C=t.getUniformLocation(n,"u_rippleEffect"),S=t.getUniformLocation(n,"u_tintOpacity"),w=t.getUniformLocation(n,"u_image"),E=t.createTexture();t.bindTexture(t.TEXTURE_2D,E);t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,e);t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.LINEAR);t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.LINEAR);t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE);t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE);this.gl_refs={gl:t,texture:E,textureSizeLoc:l,scrollYLoc:c,positionLoc:r,texcoordLoc:s,resolutionLoc:a,pageHeightLoc:u,viewportHeightLoc:d,blurRadiusLoc:f,borderRadiusLoc:m,containerPositionLoc:h,warpLoc:p,edgeIntensityLoc:g,rimIntensityLoc:v,baseIntensityLoc:_,edgeDistanceLoc:x,rimDistanceLoc:b,baseDistanceLoc:y,cornerBoostLoc:R,rippleEffectLoc:C,tintOpacityLoc:S,imageLoc:w,positionBuffer:i,texcoordBuffer:o};t.viewport(0,0,this.canvas.width,this.canvas.height);t.clearColor(0,0,0,0);t.bindBuffer(t.ARRAY_BUFFER,i);t.enableVertexAttribArray(r);t.vertexAttribPointer(r,2,t.FLOAT,!1,0,0);t.bindBuffer(t.ARRAY_BUFFER,o);t.enableVertexAttribArray(s);t.vertexAttribPointer(s,2,t.FLOAT,!1,0,0);t.uniform2f(a,this.canvas.width,this.canvas.height);t.uniform2f(l,e.width,e.height);t.uniform1f(f,window.glassControls?.blurRadius||5);t.uniform1f(m,this.borderRadius);t.uniform1f(p,this.warp?1:0);t.uniform1f(g,window.glassControls?.edgeIntensity||.01);t.uniform1f(v,window.glassControls?.rimIntensity||.05);t.uniform1f(_,window.glassControls?.baseIntensity||.01);t.uniform1f(x,window.glassControls?.edgeDistance||.15);t.uniform1f(b,window.glassControls?.rimDistance||.8);t.uniform1f(y,window.glassControls?.baseDistance||.1);t.uniform1f(R,window.glassControls?.cornerBoost||.02);t.uniform1f(C,window.glassControls?.rippleEffect||.1);t.uniform1f(S,this.tintOpacity);const L=this.getPosition();t.uniform2f(h,L.x,L.y);const D=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight),T=window.innerHeight;t.uniform1f(u,D);t.uniform1f(d,T);t.activeTexture(t.TEXTURE0);t.bindTexture(t.TEXTURE_2D,E);t.uniform1i(w,0);this.startRenderLoop()}startRenderLoop(){const e=()=>{if(!this.gl_refs.gl)return;const e=this.gl_refs.gl;e.clear(e.COLOR_BUFFER_BIT);const t=window.pageYOffset||document.documentElement.scrollTop;e.uniform1f(this.gl_refs.scrollYLoc,t);const n=this.getPosition();e.uniform2f(this.gl_refs.containerPositionLoc,n.x,n.y);e.drawArrays(e.TRIANGLES,0,6)};e();window.addEventListener("scroll",()=>e(),{passive:!0});this.render=e}createProgram(e,t,n){const i=this.compileShader(e,e.VERTEX_SHADER,t),o=this.compileShader(e,e.FRAGMENT_SHADER,n);if(!i||!o)return null;const r=e.createProgram();e.attachShader(r,i);e.attachShader(r,o);e.linkProgram(r);if(!e.getProgramParameter(r,e.LINK_STATUS)){console.error("Program link error:",e.getProgramInfoLog(r));return null}return r}compileShader(e,t,n){const i=e.createShader(t);e.shaderSource(i,n);e.compileShader(i);if(!e.getShaderParameter(i,e.COMPILE_STATUS)){console.error("Shader compile error:",e.getShaderInfoLog(i));return null}return i}}if("undefined"!=typeof window)window.Container=e;
@@ -135,6 +135,13 @@ class Container {
135
135
  }
136
136
  capturePageSnapshot() {
137
137
  console.log("Capturing page snapshot...");
138
+ const html2canvas = window.html2canvas;
139
+ if (!html2canvas) {
140
+ console.error("[PWTK] html2canvas not available, containers will not initialize");
141
+ Container.isCapturing = false;
142
+ Container.waitingForSnapshot = [];
143
+ return;
144
+ }
138
145
  html2canvas(document.body, {
139
146
  scale: 1,
140
147
  useCORS: true,
@@ -155,7 +162,7 @@ class Container {
155
162
  }
156
163
  });
157
164
  }).catch((error) => {
158
- console.error("html2canvas error:", error);
165
+ console.error("[PWTK] html2canvas error:", error);
159
166
  Container.isCapturing = false;
160
167
  Container.waitingForSnapshot = [];
161
168
  });