From 41b40172738767695806faae36fb8d27a7451368 Mon Sep 17 00:00:00 2001 From: ukimsanov Date: Thu, 23 Apr 2026 16:20:32 -0400 Subject: [PATCH] docs(shader-transitions): clarify allowTaint caveat in capture comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address Copilot review comment on #456: the old `allowTaint` doc comment said the resulting canvas is "still usable as a WebGL texture via gl.texImage2D (no pixel read-back required)", which is wrong. A tainted canvas CANNOT be uploaded to WebGL — the spec requires SecurityError on non-origin-clean sources with no opt-out. That's exactly what we observe in Safari + SVG-filter compositions, and what hyper-shader.ts's catch handler now handles via CSS crossfade. Update the comment to correctly describe the flag's effect: it only moves the failure point from html2canvas to texImage2D; the end-user UX is the same (smooth CSS fade in either case). The flag remains defensively correct for the non-taint branches where it genuinely helps (cross-origin images with `Access-Control-Allow-Origin`). No code change — comment only. Made-with: Cursor --- packages/shader-transitions/src/capture.ts | 27 ++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/shader-transitions/src/capture.ts b/packages/shader-transitions/src/capture.ts index c172b2cb3..92c277d6d 100644 --- a/packages/shader-transitions/src/capture.ts +++ b/packages/shader-transitions/src/capture.ts @@ -37,14 +37,27 @@ export function captureScene(sceneEl: HTMLElement, bgColor: string): Promise elements (e.g. feTurbulence grain backgrounds), certain // cross-origin images, and mask/clip-path url() refs can taint the // output canvas on WebKit. Without these flags, html2canvas throws - // `SecurityError: The operation is insecure` on read-back and every - // shader transition falls through to the hard-cut catch handler — - // observed in Safari + Claude Design's cross-origin iframe sandbox. + // `SecurityError: The operation is insecure` during its own read-back + // path and every shader transition falls through to the catch handler + // — observed in Safari + Claude Design's cross-origin iframe sandbox. // - // useCORS: send CORS headers on same-/cross-origin image fetches. - // allowTaint: proceed even when canvas becomes tainted; the resulting - // canvas is still usable as a WebGL texture via - // gl.texImage2D (no pixel read-back required). + // useCORS: send CORS headers on image fetches so cross-origin images + // with proper `Access-Control-Allow-Origin` don't taint the + // canvas in the first place. Strict improvement. + // allowTaint: let html2canvas complete and return a canvas even when it + // becomes tainted (instead of throwing). Important caveat: + // a tainted canvas CANNOT be uploaded to WebGL via + // `gl.texImage2D` — WebGL spec requires SecurityError on + // non-origin-clean sources, with no opt-out. So this flag + // only moves the failure point from html2canvas to the + // texImage2D call in webgl.ts. In both cases `hyper-shader.ts` + // catches the rejected promise and runs the CSS crossfade + // fallback. Net effect: the end-user UX is the same (smooth + // CSS fade in either case), but we get a cleaner, more + // predictable error site and the flag is defensively + // correct for the non-taint branches where it genuinely + // helps (e.g., `crossOrigin="anonymous"` image fetches + // that already had CORS headers). useCORS: true, allowTaint: true, ignoreElements: (el: Element) => el.tagName === "CANVAS" || el.hasAttribute("data-no-capture"),