zuljaman-banner-components 1.1.21 → 1.1.22

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.
@@ -1 +1 @@
1
- {"version":3,"file":"useWebGLRenderer.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/webgl/useWebGLRenderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5E,MAAM,MAAM,eAAe,GACvB,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAC5C,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAwBD,wBAAgB,gBAAgB,IAAI,OAAO,CAgB1C;AA+HD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,EACpD,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM;;EAqMrB"}
1
+ {"version":3,"file":"useWebGLRenderer.d.ts","sourceRoot":"","sources":["../../../../src/components/BannerRenderer/webgl/useWebGLRenderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5E,MAAM,MAAM,eAAe,GACvB,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAC5C,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAwBD,wBAAgB,gBAAgB,IAAI,OAAO,CAgB1C;AA+HD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,EACpD,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM;;EA6PrB"}
@@ -153,15 +153,22 @@ function useWebGLRenderer(canvasRef, imageUrl, effects, canvasWidth, canvasHeigh
153
153
  const renderFrameRef = (0, react_1.useRef)(null);
154
154
  const effectsRef = (0, react_1.useRef)(effects);
155
155
  effectsRef.current = effects;
156
+ // Keep the latest imageUrl reachable from inside the init/restore handlers
157
+ // (which run outside the imageUrl effect's closure).
158
+ const imageUrlRef = (0, react_1.useRef)(imageUrl);
159
+ imageUrlRef.current = imageUrl;
156
160
  // Track whether any effect needs animation (grain animated or refraction with animation)
157
161
  const needsAnimation = effects.grainAnimated && (((_a = effects.grainIntensity) !== null && _a !== void 0 ? _a : 0) > 0 ||
158
162
  ((_b = effects.refractionIntensity) !== null && _b !== void 0 ? _b : 0) > 0);
159
163
  // Load image as texture
160
- const loadTexture = (0, react_1.useCallback)((gl, url) => {
164
+ const loadTexture = (0, react_1.useCallback)((_gl, url) => {
161
165
  const img = new Image();
162
166
  img.crossOrigin = 'anonymous';
163
167
  img.onload = () => {
164
- if (!glRef.current)
168
+ // Re-read the current context — the one captured at call time may have
169
+ // been lost (and a new one restored) while the image was downloading.
170
+ const gl = glRef.current;
171
+ if (!gl)
165
172
  return;
166
173
  let texture = textureRef.current;
167
174
  if (!texture) {
@@ -226,41 +233,92 @@ function useWebGLRenderer(canvasRef, imageUrl, effects, canvasWidth, canvasHeigh
226
233
  gl.drawArrays(gl.TRIANGLES, 0, 6);
227
234
  }, []);
228
235
  renderFrameRef.current = renderFrame;
229
- // Initialize WebGL
236
+ // Initialize WebGL lazily.
237
+ //
238
+ // Defer context creation until the canvas enters the viewport, and also
239
+ // re-initialize when a previously-evicted context is needed again. Browsers
240
+ // cap simultaneous WebGL contexts per tab (~16 in Chrome) — pages that mount
241
+ // dozens of banners (e.g. the style gallery) would otherwise exhaust the
242
+ // pool and leave most canvases blank.
230
243
  (0, react_1.useEffect)(() => {
231
244
  const canvas = canvasRef.current;
232
245
  if (!canvas)
233
246
  return;
234
- const gl = canvas.getContext('webgl', {
235
- alpha: false,
236
- antialias: false,
237
- premultipliedAlpha: false,
238
- preserveDrawingBuffer: true, // Needed for toBlob() export
239
- });
240
- if (!gl) {
241
- console.warn('WebGL not available, falling back to CSS rendering');
242
- return;
247
+ const initGL = () => {
248
+ if (glRef.current)
249
+ return true; // already initialized
250
+ const gl = canvas.getContext('webgl', {
251
+ alpha: false,
252
+ antialias: false,
253
+ premultipliedAlpha: false,
254
+ preserveDrawingBuffer: true, // Needed for toBlob() export
255
+ });
256
+ if (!gl) {
257
+ console.warn('WebGL not available, falling back to CSS rendering');
258
+ return false;
259
+ }
260
+ glRef.current = gl;
261
+ const program = createProgram(gl);
262
+ if (!program)
263
+ return false;
264
+ programRef.current = program;
265
+ gl.useProgram(program);
266
+ buffersRef.current = setupGeometry(gl, program);
267
+ uniformsRef.current = getUniformLocations(gl, program);
268
+ if (imageUrlRef.current) {
269
+ imageLoadedRef.current = false;
270
+ loadTexture(gl, imageUrlRef.current);
271
+ }
272
+ return true;
273
+ };
274
+ // preventDefault on 'webglcontextlost' is required for 'webglcontextrestored' to fire.
275
+ const handleContextLost = (e) => {
276
+ e.preventDefault();
277
+ glRef.current = null;
278
+ programRef.current = null;
279
+ uniformsRef.current = null;
280
+ textureRef.current = null;
281
+ buffersRef.current = null;
282
+ imageLoadedRef.current = false;
283
+ };
284
+ const handleContextRestored = () => {
285
+ initGL();
286
+ };
287
+ canvas.addEventListener('webglcontextlost', handleContextLost);
288
+ canvas.addEventListener('webglcontextrestored', handleContextRestored);
289
+ let observer = null;
290
+ if (typeof IntersectionObserver === 'undefined') {
291
+ initGL();
292
+ }
293
+ else {
294
+ observer = new IntersectionObserver((entries) => {
295
+ for (const entry of entries) {
296
+ // Re-init whenever the canvas (re)enters view and lacks a live
297
+ // context — covers both first appearance and contexts that were
298
+ // silently dropped while offscreen.
299
+ if (entry.isIntersecting && !glRef.current)
300
+ initGL();
301
+ }
302
+ }, { rootMargin: '200px' });
303
+ observer.observe(canvas);
243
304
  }
244
- glRef.current = gl;
245
- const program = createProgram(gl);
246
- if (!program)
247
- return;
248
- programRef.current = program;
249
- gl.useProgram(program);
250
- buffersRef.current = setupGeometry(gl, program);
251
- uniformsRef.current = getUniformLocations(gl, program);
252
305
  return () => {
253
- // Cleanup all GPU resources
254
- if (textureRef.current)
255
- gl.deleteTexture(textureRef.current);
256
- if (buffersRef.current) {
257
- if (buffersRef.current.positionBuffer)
258
- gl.deleteBuffer(buffersRef.current.positionBuffer);
259
- if (buffersRef.current.texCoordBuffer)
260
- gl.deleteBuffer(buffersRef.current.texCoordBuffer);
306
+ observer === null || observer === void 0 ? void 0 : observer.disconnect();
307
+ canvas.removeEventListener('webglcontextlost', handleContextLost);
308
+ canvas.removeEventListener('webglcontextrestored', handleContextRestored);
309
+ const gl = glRef.current;
310
+ if (gl) {
311
+ if (textureRef.current)
312
+ gl.deleteTexture(textureRef.current);
313
+ if (buffersRef.current) {
314
+ if (buffersRef.current.positionBuffer)
315
+ gl.deleteBuffer(buffersRef.current.positionBuffer);
316
+ if (buffersRef.current.texCoordBuffer)
317
+ gl.deleteBuffer(buffersRef.current.texCoordBuffer);
318
+ }
319
+ if (programRef.current)
320
+ gl.deleteProgram(programRef.current);
261
321
  }
262
- if (programRef.current)
263
- gl.deleteProgram(programRef.current);
264
322
  textureRef.current = null;
265
323
  buffersRef.current = null;
266
324
  programRef.current = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuljaman-banner-components",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
4
4
  "description": "Shared banner components package for Next.js and AWS Lambda platforms",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",