{"version":3,"file":"InfinityLoop.BS5o5dwF.mjs","names":["useRef"],"sources":["https:/framerusercontent.com/modules/TtjPKTSEClNxZkIRNn5h/SY0QMaiYKCY5A3s7v74t/InfinityLoop.js"],"sourcesContent":["import{jsx as _jsx}from\"react/jsx-runtime\";import{addPropertyControls,ControlType,RenderTarget}from\"framer\";import{useEffect,useRef}from\"react\";/**\n * Infinity Loop — a wireframe lemniscate drawn as a tube.\n *\n * The path is a Gerono lemniscate, x = A·cos t, y = B·sin t·cos t, which gives\n * the horizontal figure-eight. The tube comes from stroking many copies of that\n * path offset along its own normal; a gaussian \"sheen\" band travels across\n * those strands so light appears to run around the form.\n *\n * It renders one continuous loop, so it never cuts or restarts.\n *\n * @framerSupportedLayoutWidth any\n * @framerSupportedLayoutHeight any\n * @framerIntrinsicWidth 900\n * @framerIntrinsicHeight 520\n * @framerDisableUnlink\n */export default function InfinityLoop(props){const{style}=props;const hostRef=useRef(null);const canvasRef=useRef(null);const pRef=useRef(props);pRef.current=props;useEffect(()=>{const host=hostRef.current;const canvas=canvasRef.current;if(!host||!canvas)return;const ctx=canvas.getContext(\"2d\",{alpha:false});if(!ctx)return;const TAU=Math.PI*2;const SAMPLES=260;const onCanvas=RenderTarget.current()===RenderTarget.canvas;const reduced=typeof window!==\"undefined\"&&window.matchMedia&&window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;let W=1;let H=1;let clock=0;let last=performance.now();let raf=0;let stillSig=\"\";// Canvas 2D cannot read CSS custom properties, so a var(--token-…) has to\n// be resolved against the host first. Any other colour string passes\n// through untouched.\nconst cssColour=v=>{if(typeof v!==\"string\"||!v.startsWith(\"var(\"))return v;const name=v.slice(4,-1).split(\",\")[0].trim();return getComputedStyle(host).getPropertyValue(name).trim()||v;};function sizeToHost(){const r=host.getBoundingClientRect();const dpr=Math.min(window.devicePixelRatio||1,2);const w=Math.max(1,Math.round(r.width));const h=Math.max(1,Math.round(r.height));if(w===W&&h===H&&canvas.width===Math.round(w*dpr))return;W=w;H=h;canvas.width=Math.round(W*dpr);canvas.height=Math.round(H*dpr);ctx.setTransform(dpr,0,0,dpr,0,0);}function render(animate){const p=pRef.current;ctx.globalAlpha=1;ctx.globalCompositeOperation=\"source-over\";ctx.fillStyle=cssColour(p.ground);ctx.fillRect(0,0,W,H);ctx.lineCap=\"round\";ctx.lineJoin=\"round\";const ink1=cssColour(p.ink1);const ink2=cssColour(p.ink2);// Fit the figure to the frame, then apply the user's scale.\n// Two slow, incommensurate oscillations keep the form from ever\n// repeating exactly: the tilt sways while the loops breathe.\nconst t=animate?clock*p.speed:0;const sway=p.sway?Math.sin(t*.37)*p.sway:0;const bw=p.breathe?1+Math.sin(t*.53)*p.breathe*.14:1;const bh=p.breathe?1+Math.sin(t*.41+1.3)*p.breathe*.11:1;const fit=Math.min(W/2.35,H/1.15);const A=fit*p.scale*bw;const B=A*p.squash*bh;const CX=W/2;const CY=H/2;const S=Math.max(1,Math.round(p.strands));const thick=p.thickness*A*.14;const rot=(p.rotate+sway)*Math.PI/180;const cosR=Math.cos(rot);const sinR=Math.sin(rot);// The sheen band drifts across the strands; `flow` slides the colour\n// gradient around the loop so the two move independently.\nconst sheenPos=p.sheen&&animate?Math.sin(clock*p.speed*1.1)*.92:.35;const flow=animate?clock*p.speed*.6:0;if(p.bloom){ctx.globalCompositeOperation=\"lighter\";}for(let si=0;si<S;si++){const s=S===1?0:si/(S-1)*2-1;// Gaussian highlight across the tube's cross-section.\nconst d=(s-sheenPos)/.34;const band=Math.exp(-d*d);const alpha=(p.floor+(1-p.floor)*band)*p.opacity;ctx.beginPath();for(let j=0;j<=SAMPLES;j++){const t=j/SAMPLES*TAU;const bx=A*Math.cos(t);const by=B*Math.sin(t)*Math.cos(t);// Normal of the lemniscate, for offsetting the strand.\nconst tx=-A*Math.sin(t);const ty=B*Math.cos(2*t);const L=Math.hypot(tx,ty)||1;const nx=-ty/L;const ny=tx/L;const ox=bx+nx*s*thick;const oy=by+ny*s*thick;const x=CX+ox*cosR-oy*sinR;const y=CY+ox*sinR+oy*cosR;if(j===0)ctx.moveTo(x,y);else ctx.lineTo(x,y);}ctx.closePath();if(p.gradient){// Sweep the gradient across the figure, offset by `flow`.\nconst a=flow%TAU;const gx=Math.cos(a)*A;const gy=Math.sin(a)*B;const g=ctx.createLinearGradient(CX-gx,CY-gy,CX+gx,CY+gy);if(p.mirrorGradient){// Bright at both ends, dark through the middle — the way a\n// real tube falls off, and it keeps both lobes legible when\n// the dark stop matches the ground.\ng.addColorStop(0,ink1);g.addColorStop(.5,ink2);g.addColorStop(1,ink1);}else{g.addColorStop(0,ink1);g.addColorStop(1,ink2);}ctx.strokeStyle=g;}else{ctx.strokeStyle=ink1;}ctx.globalAlpha=Math.max(0,Math.min(1,alpha));ctx.lineWidth=p.weight;ctx.stroke();}ctx.globalCompositeOperation=\"source-over\";ctx.globalAlpha=1;}function frame(now){raf=requestAnimationFrame(frame);const p=pRef.current;const dt=Math.min(.05,(now-last)/1e3);last=now;sizeToHost();const animate=!reduced&&(!onCanvas||p.animateOnCanvas);// On the Framer canvas with animation off, only repaint when a\n// property actually changed, so the editor stays responsive.\nif(!animate){const vs=JSON.stringify(p)+\"|\"+W+\"x\"+H;if(vs===stillSig)return;stillSig=vs;}else{clock+=dt;}render(animate);}const ro=new ResizeObserver(()=>{sizeToHost();stillSig=\"\";});ro.observe(host);sizeToHost();raf=requestAnimationFrame(frame);return()=>{cancelAnimationFrame(raf);ro.disconnect();};},[]);return /*#__PURE__*/_jsx(\"div\",{ref:hostRef,style:{...style,position:\"relative\",overflow:\"hidden\",background:props.ground},children:/*#__PURE__*/_jsx(\"canvas\",{ref:canvasRef,style:{width:\"100%\",height:\"100%\",display:\"block\"}})});}InfinityLoop.defaultProps={ground:\"#141414\",ink1:\"#E8B45A\",ink2:\"#2F8FE0\",gradient:true,mirrorGradient:false,strands:42,thickness:1,weight:1,scale:.86,squash:.62,rotate:-8,sway:6,breathe:.5,sheen:true,speed:.5,floor:.08,opacity:1,bloom:false,animateOnCanvas:false};addPropertyControls(InfinityLoop,{ground:{type:ControlType.Color,title:\"Ground\"},ink1:{type:ControlType.Color,title:\"Ink 1\"},ink2:{type:ControlType.Color,title:\"Ink 2\"},gradient:{type:ControlType.Boolean,title:\"Gradient\",description:\"Sweeps the stroke from Ink 1 to Ink 2 across the figure.\"},mirrorGradient:{type:ControlType.Boolean,title:\"Mirror gradient\",description:\"Ink 1 at both ends with Ink 2 through the middle, so the whole figure stays visible when Ink 2 matches the ground.\",hidden:p=>!p.gradient},strands:{type:ControlType.Number,title:\"Strands\",min:1,max:120,step:1,description:\"How many offset copies make up the tube. More reads as solid.\"},thickness:{type:ControlType.Number,title:\"Thickness\",min:0,max:3,step:.02},weight:{type:ControlType.Number,title:\"Weight\",min:.25,max:4,step:.05},scale:{type:ControlType.Number,title:\"Scale\",min:.2,max:6,step:.05,description:\"Above roughly 1.2 the figure crops past the frame and reads as abstract form rather than a symbol. Narrow frames need a much higher number than wide ones.\"},squash:{type:ControlType.Number,title:\"Squash\",min:.2,max:1.4,step:.02,description:\"Height of the loops against their width.\"},rotate:{type:ControlType.Number,title:\"Tilt\",min:-45,max:45,step:1},sway:{type:ControlType.Number,title:\"Sway\",min:0,max:30,step:.5,description:\"Degrees the tilt drifts back and forth.\"},breathe:{type:ControlType.Number,title:\"Breathe\",min:0,max:1,step:.02,description:\"How much the loops swell and contract as they turn.\"},sheen:{type:ControlType.Boolean,title:\"Sheen\",description:\"Runs a bright band around the tube, the way light moves on chrome.\"},speed:{type:ControlType.Number,title:\"Speed\",min:0,max:2,step:.01},floor:{type:ControlType.Number,title:\"Residue\",min:0,max:1,step:.01,description:\"How visible the strands are away from the sheen.\"},opacity:{type:ControlType.Number,title:\"Opacity\",min:0,max:1,step:.01},bloom:{type:ControlType.Boolean,title:\"Bloom\"},animateOnCanvas:{type:ControlType.Boolean,title:\"Animate on canvas\",description:\"Off by default so the Framer editor stays fast. Preview always animates.\"}});\nexport const __FramerMetadata__ = {\"exports\":{\"default\":{\"type\":\"reactComponent\",\"name\":\"InfinityLoop\",\"slots\":[],\"annotations\":{\"framerContractVersion\":\"1\",\"framerIntrinsicWidth\":\"900\",\"framerIntrinsicHeight\":\"520\",\"framerSupportedLayoutHeight\":\"any\",\"framerDisableUnlink\":\"\",\"framerSupportedLayoutWidth\":\"any\"}},\"__FramerMetadata__\":{\"type\":\"variable\"}}}\n//# sourceMappingURL=./InfinityLoop.map"],"mappings":"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"}