{"version":3,"file":"CursorMaskReveal.gv7lZO2X.mjs","names":["React.useRef","React.useState"],"sources":["https:/framerusercontent.com/modules/77dts2wVPEeu3XpPuaCC/5e7PeYzw1lgcGpdKBA03/CursorMaskReveal.js"],"sourcesContent":["// Cursor Follow Mask Reveal: Foreground cutout with PNG/SVG mask, revealing background, mask follows cursor\nimport{jsx as _jsx}from\"react/jsx-runtime\";import*as React from\"react\";import{addPropertyControls,ControlType,useIsOnFramerCanvas}from\"framer\";/**\n * @framerDisableUnlink\n *\n * Cursor Follow Mask Reveal\n *\n * @framerIntrinsicWidth 500\n * @framerIntrinsicHeight 350\n *\n * @framerSupportedLayoutWidth any-prefer-fixed\n * @framerSupportedLayoutHeight any-prefer-fixed\n */function CursorMaskReveal(props){const{backgroundImage={src:\"https://framerusercontent.com/images/GfGkADagM4KEibNcIiRUWlfrR0.jpg\",alt:\"Background\"},foregroundImage={src:\"https://framerusercontent.com/images/aNsAT3jCvt4zglbWCUoFe33Q.jpg\",alt:\"Foreground\"},maskType=\"png\",maskImagePNG=\"https://framerusercontent.com/images/GfGkADagM4KEibNcIiRUWlfrR0.jpg\",maskImageSVG=\"https://framerusercontent.com/images/GfGkADagM4KEibNcIiRUWlfrR0.jpg\",maskWidth=120,overlayColor=\"#000000\"}=props;const containerRef=React.useRef(null);const canvasRef=React.useRef(null);const[maskAspect,setMaskAspect]=React.useState(1);const[containerSize,setContainerSize]=React.useState({w:500,h:350});const[maskPos,setMaskPos]=React.useState({x:.5,y:.5});const[isInside,setIsInside]=React.useState(false);const isOnCanvas=useIsOnFramerCanvas();// Get current mask source based on type\nconst currentMaskSrc=maskType===\"png\"?maskImagePNG:maskImageSVG;// Load images\nconst[images,setImages]=React.useState({bg:null,fg:null,mask:null});React.useEffect(()=>{if(typeof window===\"undefined\")return;let loaded={bg:null,fg:null,mask:null};let done=0;function check(){done++;if(done===3)setImages(loaded);}const bg=new window.Image;bg.crossOrigin=\"anonymous\";bg.onload=check;bg.onerror=check;bg.src=backgroundImage.src;loaded.bg=bg;const fg=new window.Image;fg.crossOrigin=\"anonymous\";fg.onload=check;fg.onerror=check;fg.src=foregroundImage.src;loaded.fg=fg;const mask=new window.Image;mask.crossOrigin=\"anonymous\";mask.onload=()=>{setMaskAspect(mask.width/mask.height);loaded.mask=mask;check();};mask.onerror=()=>{setMaskAspect(1);loaded.mask=mask;check();};mask.src=currentMaskSrc;loaded.mask=mask;},[backgroundImage.src,foregroundImage.src,currentMaskSrc]);// Track container size with ResizeObserver\nReact.useLayoutEffect(()=>{if(!containerRef.current||typeof window===\"undefined\")return;const ref=containerRef.current;function updateSize(){const rect=ref.getBoundingClientRect();setContainerSize({w:Math.round(rect.width),h:Math.round(rect.height)});}updateSize();const ro=new window.ResizeObserver(updateSize);ro.observe(ref);return()=>ro.disconnect();},[]);// Mouse move handler\nReact.useEffect(()=>{if(isOnCanvas||typeof window===\"undefined\")return;const ref=containerRef.current;if(!ref)return;let lastMouse={x:null,y:null};function updateMaskFromPointer(clientX,clientY){lastMouse.x=clientX;lastMouse.y=clientY;const rect=ref.getBoundingClientRect();let x=clientX-rect.left;let y=clientY-rect.top;if(x>=0&&x<=rect.width&&y>=0&&y<=rect.height){setIsInside(true);setMaskPos({x:x/rect.width,y:y/rect.height});}else{setIsInside(false);}}function handlePointerMove(e){updateMaskFromPointer(e.clientX,e.clientY);}function handlePointerLeave(){setIsInside(false);}function handleScroll(){if(lastMouse.x!==null&&lastMouse.y!==null){const rect=ref.getBoundingClientRect();let x=lastMouse.x-rect.left;let y=lastMouse.y-rect.top;if(x>=0&&x<=rect.width&&y>=0&&y<=rect.height){setIsInside(true);setMaskPos({x:x/rect.width,y:y/rect.height});}else{setIsInside(false);}}}ref.addEventListener(\"pointermove\",handlePointerMove);ref.addEventListener(\"pointerleave\",handlePointerLeave);window.addEventListener(\"scroll\",handleScroll,true);return()=>{ref.removeEventListener(\"pointermove\",handlePointerMove);ref.removeEventListener(\"pointerleave\",handlePointerLeave);window.removeEventListener(\"scroll\",handleScroll,true);};},[isOnCanvas]);// Draw to canvas\nReact.useEffect(()=>{const{w,h}=containerSize;const ctx=canvasRef.current?.getContext(\"2d\");if(!ctx||!images.bg||!images.fg||!images.mask)return;ctx.clearRect(0,0,w,h);// Draw foreground (cover)\ndrawCover(ctx,images.fg,w,h);// Overlay color on foreground (now using alpha from overlayColor)\nif(overlayColor&&overlayColor.length>0){ctx.save();ctx.globalAlpha=1;ctx.globalCompositeOperation=\"source-over\";ctx.fillStyle=overlayColor;ctx.fillRect(0,0,w,h);ctx.restore();}// Prepare mask size/pos\nconst maskW=maskWidth;const maskH=maskWidth/maskAspect;const halfW=maskW/2;const halfH=maskH/2;if(isInside){let cx=maskPos.x*w;let cy=maskPos.y*h;// Set composite to destination-out to punch hole (including overlay)\nctx.save();ctx.globalCompositeOperation=\"destination-out\";ctx.drawImage(images.mask,cx-halfW,cy-halfH,maskW,maskH);ctx.restore();// Draw background only in the hole\nctx.save();ctx.globalCompositeOperation=\"destination-over\";drawCover(ctx,images.bg,w,h);ctx.restore();}},[images,containerSize,maskPos,maskWidth,maskAspect,isInside,overlayColor]);// Helper: draw image with object-fit: cover\nfunction drawCover(ctx,img,w,h){const iw=img.width;const ih=img.height;if(iw===0||ih===0)return;const scale=Math.max(w/iw,h/ih);const dw=iw*scale;const dh=ih*scale;const dx=(w-dw)/2;const dy=(h-dh)/2;ctx.drawImage(img,0,0,iw,ih,dx,dy,dw,dh);}return /*#__PURE__*/_jsx(\"div\",{ref:containerRef,style:{...props.style,width:props.style&&props.style.width!==undefined?props.style.width:500,height:props.style&&props.style.height!==undefined?props.style.height:350,position:\"relative\",overflow:\"hidden\",touchAction:\"none\",userSelect:\"none\"},children:/*#__PURE__*/_jsx(\"canvas\",{ref:canvasRef,width:containerSize.w,height:containerSize.h,style:{width:\"100%\",height:\"100%\",display:\"block\"}})});}addPropertyControls(CursorMaskReveal,{backgroundImage:{type:ControlType.ResponsiveImage,title:\"Background\"},foregroundImage:{type:ControlType.ResponsiveImage,title:\"Foreground\"},maskType:{type:ControlType.Enum,title:\"Mask Type\",options:[\"png\",\"svg\"],optionTitles:[\"PNG\",\"SVG\"],defaultValue:\"png\",displaySegmentedControl:true},maskImagePNG:{type:ControlType.File,allowedFileTypes:[\"png\",\"svg\"],title:\"Mask Upload\",hidden:({maskType})=>maskType!==\"png\"},maskImageSVG:{type:ControlType.File,allowedFileTypes:[\"svg\",\"png\"],title:\"Mask Upload\",hidden:({maskType})=>maskType!==\"svg\"},maskWidth:{type:ControlType.Number,title:\"Mask Width\",defaultValue:120,min:20,max:800,step:1,unit:\"px\"},overlayColor:{type:ControlType.Color,title:\"Overlay Color\",defaultValue:\"#00000000\"}});export default CursorMaskReveal;\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"CursorMaskReveal\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerDisableUnlink\":\"*\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./CursorMaskReveal.map"],"mappings":"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"}