https://motioncanvas.online/preview/semantic-warp-lens
Scroll Down

Loading Canvas Shader...

Next-Gen Scroll Mechanics

Experience Beautiful Ambient Depth

This browser window is simulating a production webpage. As you scroll down, the ambient Semantic Warp Lens background dynamically zooms and pulls focus in real-time, creating beautiful, cinematic parallax depth.

Built for Ultra Performance

Modern web layouts require buttery-smooth animations. Our styles run completely on the GPU, avoiding CPU reflow and main-thread layout jank.

Focus Pull Parallax

Scroll depth controls blur intensity and lens scaling simultaneously to guide focus elegantly.

GPU-Accelerated

Uses hardware transforms and native filters, optimized for stable 120fps scrolling.

Highly Customizable

Adjust speed, maximum blur limit, zoom multipliers, and filters in real-time.

© 2026 MOTIONCANVAS. ALL RIGHTS RESERVED.ACTIVE BACKGROUND: SEMANTIC WARP LENS

Semantic Warp Lens

🔵 Interactive

A gorgeous, high-fidelity monospaced text grid that warps, rotates, and inverts colors like an optical lens centered directly on the user's cursor.

#interactive#spring-physics#lens-distortion#typography#color-inversion#canvas
Advertisement
Sponsor Advertisement
728 × 90 | Responsive Banner

Responsive Horizontal Leaderboard

Slot ID: ca-pub-detail-below-preview

Google AdSense Placeholder

Interactive Settings

Motion PresetsCustom Tuning
Animation Speed1.0x
Blur (Aesthetic diffusion)0px
Layer Opacity100%
Scale Zoom1.0x
Rotation Angle0°
Advertisement
Sponsor Advertisement
300 × 250 | Rectangle

Medium Rectangle Block

Slot ID: ca-pub-detail-after-customization

Google AdSense Placeholder

Quick Copy Actions

Download File Packages

Keyboard Shortcuts

Space Play/Pause
F Fullscreen
R Reset Slider
C Copy Code
Advertisement
Sponsor Advertisement
728 × 90 | Responsive Banner

Responsive Horizontal Leaderboard

Slot ID: ca-pub-detail-before-related

Google AdSense Placeholder

More in Interactive & Cursor-Driven

Semantic Warp Lens - HTML5 Canvas & JavaScript Interactive & Cursor-Driven background for React & Tailwind

Integrate the Semantic Warp Lens directly into your website. This asset is rendered using HTML5 Canvas 2D render loop. It is optimized for zero layout-shifts and runs with high-performance hardware-accelerated processing.

Performance Specifications

  • Render Mode: INTERACTIVE (HTML5 Canvas & JavaScript)
  • Fluidity: Locked at 60fps dynamic loop
  • Bundle Footprint: Zero external NPM dependencies
  • SEO Indexing status: 100% Crawlable static semantic HTML

🛠️ Integration Capabilities

Our templates expose inline design tokens like --color-1 and --color-2 for infinite color palettes. This template is designed to fit inside hero elements, full-screen landing pages, and interactive presentation cards.

Technical Code Reference & Syntaxes for Googlebot & Crawlers

The snippets below display the direct, unminified source code utilized for rendering this background.

HTML & Inline CSS Snippet (Vanilla)

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Semantic Warp Lens</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
      background: #09090b;
    }
    
    .semantic-lens-container {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: #08090c;
      overflow: hidden;
    }
    #canvas-semantic-warp-lens {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      border: none;
      display: block;
    }
  </style>
</head>
<body>

  <div class="semantic-lens-container">
    <canvas id="canvas-semantic-warp-lens"></canvas>
  </div>
  <script>
  (function() {
    const canvas = document.getElementById('canvas-semantic-warp-lens');
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;
  
    let cols = 0;
    let rows = 0;
    let nodes = [];
    
    const spacingX = 14;
    const spacingY = 22;
    const textPattern = "SEMANTIC-WARP-LENS-MOTION-CANVAS-CREATIVE-DYNAMICS-60FPS-PLAYGROUND-";
    
    const springK = 0.082;
    const friction = 0.81;
    const radius = 120;
    const rSq = radius * radius;
  
    let mouseX = -1000;
    let mouseY = -1000;
    let targetMouseX = -1000;
    let targetMouseY = -1000;
  
    function initNodes() {
      const width = canvas.width;
      const height = canvas.height;
      
      cols = Math.ceil(width / spacingX) + 1;
      rows = Math.ceil(height / spacingY) + 1;
      nodes = [];
  
      const offsetX = (width - (cols - 1) * spacingX) / 2;
      const offsetY = (height - (rows - 1) * spacingY) / 2;
  
      let charIdx = 0;
      for (let r = 0; r < rows; r++) {
        for (let c = 0; c < cols; c++) {
          const ox = offsetX + c * spacingX;
          const oy = offsetY + r * spacingY;
          const char = textPattern.charAt(charIdx % textPattern.length);
          charIdx++;
          
          nodes.push({
            x: ox,
            y: oy,
            ox: ox,
            oy: oy,
            vx: 0,
            vy: 0,
            disp: 0,
            mouseDist: 99999,
            char: char
          });
        }
      }
    }
  
    function resize() {
      const rect = canvas.parentNode ? canvas.parentNode.getBoundingClientRect() : null;
      const width = rect ? rect.width : window.innerWidth;
      const height = rect ? rect.height : window.innerHeight;
      
      if (canvas.width !== width || canvas.height !== height) {
        canvas.width = width;
        canvas.height = height;
        initNodes();
      }
    }
  
    function onMouseMove(e) {
      const rect = canvas.getBoundingClientRect();
      targetMouseX = e.clientX - rect.left;
      targetMouseY = e.clientY - rect.top;
    }
  
    function onMouseLeave() {
      targetMouseX = -1000;
      targetMouseY = -1000;
    }
  
    function onTouchMove(e) {
      if (e.touches.length > 0) {
        const touch = e.touches[0];
        const rect = canvas.getBoundingClientRect();
        targetMouseX = touch.clientX - rect.left;
        targetMouseY = touch.clientY - rect.top;
      }
    }
  
    function onTouchEnd() {
      targetMouseX = -1000;
      targetMouseY = -1000;
    }
  
    window.addEventListener('resize', resize);
    window.addEventListener('mousemove', onMouseMove);
    window.addEventListener('mouseleave', onMouseLeave);
    window.addEventListener('touchmove', onTouchMove, { passive: true });
    window.addEventListener('touchstart', onTouchMove, { passive: true });
    window.addEventListener('touchend', onTouchEnd);
    window.addEventListener('touchcancel', onTouchEnd);
  
    let observer;
    if (canvas.parentNode) {
      observer = new MutationObserver(resize);
      observer.observe(canvas.parentNode, { attributes: true });
    }
  
    resize();
  
    function cleanup() {
      window.removeEventListener('resize', resize);
      window.removeEventListener('mousemove', onMouseMove);
      window.removeEventListener('mouseleave', onMouseLeave);
      window.removeEventListener('touchmove', onTouchMove);
      window.removeEventListener('touchstart', onTouchMove);
      window.removeEventListener('touchend', onTouchEnd);
      window.removeEventListener('touchcancel', onTouchEnd);
      if (observer) {
        observer.disconnect();
      }
    }
  
    function update() {
      if (targetMouseX === -1000) {
        mouseX = -1000;
        mouseY = -1000;
      } else {
        if (mouseX === -1000) {
          mouseX = targetMouseX;
          mouseY = targetMouseY;
        } else {
          mouseX += (targetMouseX - mouseX) * 0.16;
          mouseY += (targetMouseY - mouseY) * 0.16;
        }
      }
  
      for (let i = 0; i < nodes.length; i++) {
        const node = nodes[i];
        let tx = node.ox;
        let ty = node.oy;
        let dist = 99999;
  
        if (mouseX !== -1000) {
          const dx = node.ox - mouseX;
          const dy = node.oy - mouseY;
          const distSq = dx * dx + dy * dy;
  
          if (distSq < rSq) {
            dist = Math.sqrt(distSq) || 0.001;
            const t = dist / radius;
            const pull = (1.0 - t) * (1.0 - t) * 0.65;
            
            // Warp towards cursor
            let rx = -dx * pull;
            let ry = -dy * pull;
  
            // Inside absolute center: gravity spiral swirl
            if (dist < 40) {
              const swirl = (1.0 - dist / 40) * 0.5;
              const cosS = Math.cos(swirl);
              const sinS = Math.sin(swirl);
              const rxNew = rx * cosS - ry * sinS;
              const ryNew = rx * sinS + ry * cosS;
              rx = rxNew;
              ry = ryNew;
            }
  
            tx = node.ox + rx;
            ty = node.oy + ry;
          }
        }
  
        const ax = (tx - node.x) * springK;
        const ay = (ty - node.y) * springK;
  
        node.vx = (node.vx + ax) * friction;
        node.vy = (node.vy + ay) * friction;
  
        node.x += node.vx;
        node.y += node.vy;
  
        node.disp = Math.hypot(node.x - node.ox, node.y - node.oy);
        node.mouseDist = dist;
      }
    }
  
    function draw() {
      ctx.fillStyle = '#08090b';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
  
      if (mouseX !== -1000) {
        ctx.beginPath();
        const glow = ctx.createRadialGradient(mouseX, mouseY, 0, mouseX, mouseY, radius * 1.5);
        glow.addColorStop(0, 'rgba(168, 85, 247, 0.08)');
        glow.addColorStop(0.5, 'rgba(56, 189, 248, 0.02)');
        glow.addColorStop(1, 'rgba(0, 0, 0, 0)');
        ctx.fillStyle = glow;
        ctx.arc(mouseX, mouseY, radius * 1.5, 0, Math.PI * 2);
        ctx.fill();
      }
  
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
  
      const normalFont = 'bold 12px "JetBrains Mono", "Fira Code", monospace';
      const warpedFont = 'bold 14px "JetBrains Mono", "Fira Code", monospace';
  
      for (let i = 0; i < nodes.length; i++) {
        const node = nodes[i];
        
        if (node.disp < 0.1 && (mouseX === -1000 || node.mouseDist > radius)) {
          ctx.font = normalFont;
          ctx.fillStyle = 'rgba(148, 163, 184, 0.22)';
          ctx.fillText(node.char, node.ox, node.oy);
        } else {
          const dist = node.mouseDist;
          
          if (dist < radius) {
            const t = 1.0 - (dist / radius);
            
            ctx.save();
            ctx.translate(node.x, node.y);
            
            const angle = (node.vx + node.vy) * 0.035;
            ctx.rotate(angle);
            
            const scale = 1.0 + t * 0.55;
            ctx.scale(scale, scale);
            
            if (dist < 35) {
              ctx.fillStyle = '#ffffff';
              ctx.shadowColor = '#e879f9';
              ctx.shadowBlur = 8;
              ctx.font = warpedFont;
            } else if (dist < 75) {
              ctx.fillStyle = 'rgba(168, 85, 247, 0.95)';
              ctx.shadowBlur = 0;
              ctx.font = warpedFont;
            } else {
              ctx.fillStyle = 'rgba(56, 189, 248, 0.75)';
              ctx.shadowBlur = 0;
              ctx.font = normalFont;
            }
            
            ctx.fillText(node.char, 0, 0);
            ctx.restore();
          } else {
            ctx.font = normalFont;
            const snapProgress = Math.min(node.disp / 30, 1.0);
            const r = Math.floor(148 + snapProgress * (56 - 148));
            const g = Math.floor(163 + snapProgress * (189 - 163));
            const b = Math.floor(184 + snapProgress * (248 - 184));
            const alpha = 0.2 + snapProgress * 0.25;
            
            ctx.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
            ctx.fillText(node.char, node.x, node.y);
          }
        }
      }
    }
  
    function render() {
      if (!canvas.isConnected) {
        cleanup();
        return;
      }
  
      update();
      draw();
      requestAnimationFrame(render);
    }
  
    requestAnimationFrame(render);
  })();
  </script>

  
  <script>
    // Throttled interactive cursor coordinates mapping
    (function() {
      document.documentElement.style.setProperty('--mouse-x', '0');
      document.documentElement.style.setProperty('--mouse-y', '0');

      let targetX = 0, targetY = 0;
      let currentX = 0, currentY = 0;

      window.addEventListener('mousemove', (e) => {
        targetX = (e.clientX / window.innerWidth) - 0.5;
        targetY = (e.clientY / window.innerHeight) - 0.5;
      });

      window.addEventListener('mouseleave', () => {
        targetX = 0;
        targetY = 0;
      });

      function update() {
        currentX += (targetX - currentX) * 0.08;
        currentY += (targetY - currentY) * 0.08;
        
        document.documentElement.style.setProperty('--mouse-x', currentX.toFixed(4));
        document.documentElement.style.setProperty('--mouse-y', currentY.toFixed(4));
        
        requestAnimationFrame(update);
      }
      requestAnimationFrame(update);
    })();
  </script>
  
</body>
</html>

React Component Wrapper (TSX)

import React, { useEffect, useRef } from 'react';

export default function SemanticWarpLensBackground() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    let targetX = 0, targetY = 0;
    let currentX = 0, currentY = 0;
    let frameId: number;

    const handleMouseMove = (e: MouseEvent) => {
      targetX = (e.clientX / window.innerWidth) - 0.5;
      targetY = (e.clientY / window.innerHeight) - 0.5;
    };

    const handleMouseLeave = () => {
      targetX = 0;
      targetY = 0;
    };

    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseleave', handleMouseLeave);

    const updateCoordinates = () => {
      currentX += (targetX - currentX) * 0.08;
      currentY += (targetY - currentY) * 0.08;

      if (containerRef.current) {
        containerRef.current.style.setProperty('--mouse-x', currentX.toFixed(4));
        containerRef.current.style.setProperty('--mouse-y', currentY.toFixed(4));
      }
      frameId = requestAnimationFrame(updateCoordinates);
    };
    
    frameId = requestAnimationFrame(updateCoordinates);

    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseleave', handleMouseLeave);
      cancelAnimationFrame(frameId);
    };
  }, []);

  return (
    <div 
      ref={containerRef} 
      style={{ width: '100%', height: '100%', position: 'relative', overflow: 'hidden' }}
    >
      <style dangerouslySetInnerHTML={{ __html: `
        .semantic-lens-container {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: #08090c;
          overflow: hidden;
        }
        #canvas-semantic-warp-lens {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          border: none;
          display: block;
        }
      ` }} />
      
      {/* HTML Structure */}
      <div 
        style={{ width: '100%', height: '100%' }}
        dangerouslySetInnerHTML={{ __html: `
          <div class="semantic-lens-container">
            <canvas id="canvas-semantic-warp-lens"></canvas>
          </div>
          <script>
          (function() {
            const canvas = document.getElementById('canvas-semantic-warp-lens');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
          
            let cols = 0;
            let rows = 0;
            let nodes = [];
            
            const spacingX = 14;
            const spacingY = 22;
            const textPattern = "SEMANTIC-WARP-LENS-MOTION-CANVAS-CREATIVE-DYNAMICS-60FPS-PLAYGROUND-";
            
            const springK = 0.082;
            const friction = 0.81;
            const radius = 120;
            const rSq = radius * radius;
          
            let mouseX = -1000;
            let mouseY = -1000;
            let targetMouseX = -1000;
            let targetMouseY = -1000;
          
            function initNodes() {
              const width = canvas.width;
              const height = canvas.height;
              
              cols = Math.ceil(width / spacingX) + 1;
              rows = Math.ceil(height / spacingY) + 1;
              nodes = [];
          
              const offsetX = (width - (cols - 1) * spacingX) / 2;
              const offsetY = (height - (rows - 1) * spacingY) / 2;
          
              let charIdx = 0;
              for (let r = 0; r < rows; r++) {
                for (let c = 0; c < cols; c++) {
                  const ox = offsetX + c * spacingX;
                  const oy = offsetY + r * spacingY;
                  const char = textPattern.charAt(charIdx % textPattern.length);
                  charIdx++;
                  
                  nodes.push({
                    x: ox,
                    y: oy,
                    ox: ox,
                    oy: oy,
                    vx: 0,
                    vy: 0,
                    disp: 0,
                    mouseDist: 99999,
                    char: char
                  });
                }
              }
            }
          
            function resize() {
              const rect = canvas.parentNode ? canvas.parentNode.getBoundingClientRect() : null;
              const width = rect ? rect.width : window.innerWidth;
              const height = rect ? rect.height : window.innerHeight;
              
              if (canvas.width !== width || canvas.height !== height) {
                canvas.width = width;
                canvas.height = height;
                initNodes();
              }
            }
          
            function onMouseMove(e) {
              const rect = canvas.getBoundingClientRect();
              targetMouseX = e.clientX - rect.left;
              targetMouseY = e.clientY - rect.top;
            }
          
            function onMouseLeave() {
              targetMouseX = -1000;
              targetMouseY = -1000;
            }
          
            function onTouchMove(e) {
              if (e.touches.length > 0) {
                const touch = e.touches[0];
                const rect = canvas.getBoundingClientRect();
                targetMouseX = touch.clientX - rect.left;
                targetMouseY = touch.clientY - rect.top;
              }
            }
          
            function onTouchEnd() {
              targetMouseX = -1000;
              targetMouseY = -1000;
            }
          
            window.addEventListener('resize', resize);
            window.addEventListener('mousemove', onMouseMove);
            window.addEventListener('mouseleave', onMouseLeave);
            window.addEventListener('touchmove', onTouchMove, { passive: true });
            window.addEventListener('touchstart', onTouchMove, { passive: true });
            window.addEventListener('touchend', onTouchEnd);
            window.addEventListener('touchcancel', onTouchEnd);
          
            let observer;
            if (canvas.parentNode) {
              observer = new MutationObserver(resize);
              observer.observe(canvas.parentNode, { attributes: true });
            }
          
            resize();
          
            function cleanup() {
              window.removeEventListener('resize', resize);
              window.removeEventListener('mousemove', onMouseMove);
              window.removeEventListener('mouseleave', onMouseLeave);
              window.removeEventListener('touchmove', onTouchMove);
              window.removeEventListener('touchstart', onTouchMove);
              window.removeEventListener('touchend', onTouchEnd);
              window.removeEventListener('touchcancel', onTouchEnd);
              if (observer) {
                observer.disconnect();
              }
            }
          
            function update() {
              if (targetMouseX === -1000) {
                mouseX = -1000;
                mouseY = -1000;
              } else {
                if (mouseX === -1000) {
                  mouseX = targetMouseX;
                  mouseY = targetMouseY;
                } else {
                  mouseX += (targetMouseX - mouseX) * 0.16;
                  mouseY += (targetMouseY - mouseY) * 0.16;
                }
              }
          
              for (let i = 0; i < nodes.length; i++) {
                const node = nodes[i];
                let tx = node.ox;
                let ty = node.oy;
                let dist = 99999;
          
                if (mouseX !== -1000) {
                  const dx = node.ox - mouseX;
                  const dy = node.oy - mouseY;
                  const distSq = dx * dx + dy * dy;
          
                  if (distSq < rSq) {
                    dist = Math.sqrt(distSq) || 0.001;
                    const t = dist / radius;
                    const pull = (1.0 - t) * (1.0 - t) * 0.65;
                    
                    // Warp towards cursor
                    let rx = -dx * pull;
                    let ry = -dy * pull;
          
                    // Inside absolute center: gravity spiral swirl
                    if (dist < 40) {
                      const swirl = (1.0 - dist / 40) * 0.5;
                      const cosS = Math.cos(swirl);
                      const sinS = Math.sin(swirl);
                      const rxNew = rx * cosS - ry * sinS;
                      const ryNew = rx * sinS + ry * cosS;
                      rx = rxNew;
                      ry = ryNew;
                    }
          
                    tx = node.ox + rx;
                    ty = node.oy + ry;
                  }
                }
          
                const ax = (tx - node.x) * springK;
                const ay = (ty - node.y) * springK;
          
                node.vx = (node.vx + ax) * friction;
                node.vy = (node.vy + ay) * friction;
          
                node.x += node.vx;
                node.y += node.vy;
          
                node.disp = Math.hypot(node.x - node.ox, node.y - node.oy);
                node.mouseDist = dist;
              }
            }
          
            function draw() {
              ctx.fillStyle = '#08090b';
              ctx.fillRect(0, 0, canvas.width, canvas.height);
          
              if (mouseX !== -1000) {
                ctx.beginPath();
                const glow = ctx.createRadialGradient(mouseX, mouseY, 0, mouseX, mouseY, radius * 1.5);
                glow.addColorStop(0, 'rgba(168, 85, 247, 0.08)');
                glow.addColorStop(0.5, 'rgba(56, 189, 248, 0.02)');
                glow.addColorStop(1, 'rgba(0, 0, 0, 0)');
                ctx.fillStyle = glow;
                ctx.arc(mouseX, mouseY, radius * 1.5, 0, Math.PI * 2);
                ctx.fill();
              }
          
              ctx.textAlign = 'center';
              ctx.textBaseline = 'middle';
          
              const normalFont = 'bold 12px "JetBrains Mono", "Fira Code", monospace';
              const warpedFont = 'bold 14px "JetBrains Mono", "Fira Code", monospace';
          
              for (let i = 0; i < nodes.length; i++) {
                const node = nodes[i];
                
                if (node.disp < 0.1 && (mouseX === -1000 || node.mouseDist > radius)) {
                  ctx.font = normalFont;
                  ctx.fillStyle = 'rgba(148, 163, 184, 0.22)';
                  ctx.fillText(node.char, node.ox, node.oy);
                } else {
                  const dist = node.mouseDist;
                  
                  if (dist < radius) {
                    const t = 1.0 - (dist / radius);
                    
                    ctx.save();
                    ctx.translate(node.x, node.y);
                    
                    const angle = (node.vx + node.vy) * 0.035;
                    ctx.rotate(angle);
                    
                    const scale = 1.0 + t * 0.55;
                    ctx.scale(scale, scale);
                    
                    if (dist < 35) {
                      ctx.fillStyle = '#ffffff';
                      ctx.shadowColor = '#e879f9';
                      ctx.shadowBlur = 8;
                      ctx.font = warpedFont;
                    } else if (dist < 75) {
                      ctx.fillStyle = 'rgba(168, 85, 247, 0.95)';
                      ctx.shadowBlur = 0;
                      ctx.font = warpedFont;
                    } else {
                      ctx.fillStyle = 'rgba(56, 189, 248, 0.75)';
                      ctx.shadowBlur = 0;
                      ctx.font = normalFont;
                    }
                    
                    ctx.fillText(node.char, 0, 0);
                    ctx.restore();
                  } else {
                    ctx.font = normalFont;
                    const snapProgress = Math.min(node.disp / 30, 1.0);
                    const r = Math.floor(148 + snapProgress * (56 - 148));
                    const g = Math.floor(163 + snapProgress * (189 - 163));
                    const b = Math.floor(184 + snapProgress * (248 - 184));
                    const alpha = 0.2 + snapProgress * 0.25;
                    
                    ctx.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
                    ctx.fillText(node.char, node.x, node.y);
                  }
                }
              }
            }
          
            function render() {
              if (!canvas.isConnected) {
                cleanup();
                return;
              }
          
              update();
              draw();
              requestAnimationFrame(render);
            }
          
            requestAnimationFrame(render);
          })();
          </script>
        ` }}
      />
    </div>
  );
}

Next.js App Router Component (use client)

'use client';

import React, { useEffect, useRef } from 'react';

export default function SemanticWarpLensBackground() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    let targetX = 0, targetY = 0;
    let currentX = 0, currentY = 0;
    let frameId: number;

    const handleMouseMove = (e: MouseEvent) => {
      targetX = (e.clientX / window.innerWidth) - 0.5;
      targetY = (e.clientY / window.innerHeight) - 0.5;
    };

    const handleMouseLeave = () => {
      targetX = 0;
      targetY = 0;
    };

    window.addEventListener('mousemove', handleMouseMove);
    window.addEventListener('mouseleave', handleMouseLeave);

    const updateCoordinates = () => {
      currentX += (targetX - currentX) * 0.08;
      currentY += (targetY - currentY) * 0.08;

      if (containerRef.current) {
        containerRef.current.style.setProperty('--mouse-x', currentX.toFixed(4));
        containerRef.current.style.setProperty('--mouse-y', currentY.toFixed(4));
      }
      frameId = requestAnimationFrame(updateCoordinates);
    };
    
    frameId = requestAnimationFrame(updateCoordinates);

    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseleave', handleMouseLeave);
      cancelAnimationFrame(frameId);
    };
  }, []);

  return (
    <div 
      ref={containerRef} 
      className="w-full h-full relative overflow-hidden"
    >
      <style dangerouslySetInnerHTML={{ __html: `
        .semantic-lens-container {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: #08090c;
          overflow: hidden;
        }
        #canvas-semantic-warp-lens {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          border: none;
          display: block;
        }
      ` }} />
      
      {/* HTML Structure */}
      <div 
        className="w-full h-full"
        dangerouslySetInnerHTML={{ __html: `
          <div class="semantic-lens-container">
            <canvas id="canvas-semantic-warp-lens"></canvas>
          </div>
          <script>
          (function() {
            const canvas = document.getElementById('canvas-semantic-warp-lens');
            if (!canvas) return;
            const ctx = canvas.getContext('2d');
            if (!ctx) return;
          
            let cols = 0;
            let rows = 0;
            let nodes = [];
            
            const spacingX = 14;
            const spacingY = 22;
            const textPattern = "SEMANTIC-WARP-LENS-MOTION-CANVAS-CREATIVE-DYNAMICS-60FPS-PLAYGROUND-";
            
            const springK = 0.082;
            const friction = 0.81;
            const radius = 120;
            const rSq = radius * radius;
          
            let mouseX = -1000;
            let mouseY = -1000;
            let targetMouseX = -1000;
            let targetMouseY = -1000;
          
            function initNodes() {
              const width = canvas.width;
              const height = canvas.height;
              
              cols = Math.ceil(width / spacingX) + 1;
              rows = Math.ceil(height / spacingY) + 1;
              nodes = [];
          
              const offsetX = (width - (cols - 1) * spacingX) / 2;
              const offsetY = (height - (rows - 1) * spacingY) / 2;
          
              let charIdx = 0;
              for (let r = 0; r < rows; r++) {
                for (let c = 0; c < cols; c++) {
                  const ox = offsetX + c * spacingX;
                  const oy = offsetY + r * spacingY;
                  const char = textPattern.charAt(charIdx % textPattern.length);
                  charIdx++;
                  
                  nodes.push({
                    x: ox,
                    y: oy,
                    ox: ox,
                    oy: oy,
                    vx: 0,
                    vy: 0,
                    disp: 0,
                    mouseDist: 99999,
                    char: char
                  });
                }
              }
            }
          
            function resize() {
              const rect = canvas.parentNode ? canvas.parentNode.getBoundingClientRect() : null;
              const width = rect ? rect.width : window.innerWidth;
              const height = rect ? rect.height : window.innerHeight;
              
              if (canvas.width !== width || canvas.height !== height) {
                canvas.width = width;
                canvas.height = height;
                initNodes();
              }
            }
          
            function onMouseMove(e) {
              const rect = canvas.getBoundingClientRect();
              targetMouseX = e.clientX - rect.left;
              targetMouseY = e.clientY - rect.top;
            }
          
            function onMouseLeave() {
              targetMouseX = -1000;
              targetMouseY = -1000;
            }
          
            function onTouchMove(e) {
              if (e.touches.length > 0) {
                const touch = e.touches[0];
                const rect = canvas.getBoundingClientRect();
                targetMouseX = touch.clientX - rect.left;
                targetMouseY = touch.clientY - rect.top;
              }
            }
          
            function onTouchEnd() {
              targetMouseX = -1000;
              targetMouseY = -1000;
            }
          
            window.addEventListener('resize', resize);
            window.addEventListener('mousemove', onMouseMove);
            window.addEventListener('mouseleave', onMouseLeave);
            window.addEventListener('touchmove', onTouchMove, { passive: true });
            window.addEventListener('touchstart', onTouchMove, { passive: true });
            window.addEventListener('touchend', onTouchEnd);
            window.addEventListener('touchcancel', onTouchEnd);
          
            let observer;
            if (canvas.parentNode) {
              observer = new MutationObserver(resize);
              observer.observe(canvas.parentNode, { attributes: true });
            }
          
            resize();
          
            function cleanup() {
              window.removeEventListener('resize', resize);
              window.removeEventListener('mousemove', onMouseMove);
              window.removeEventListener('mouseleave', onMouseLeave);
              window.removeEventListener('touchmove', onTouchMove);
              window.removeEventListener('touchstart', onTouchMove);
              window.removeEventListener('touchend', onTouchEnd);
              window.removeEventListener('touchcancel', onTouchEnd);
              if (observer) {
                observer.disconnect();
              }
            }
          
            function update() {
              if (targetMouseX === -1000) {
                mouseX = -1000;
                mouseY = -1000;
              } else {
                if (mouseX === -1000) {
                  mouseX = targetMouseX;
                  mouseY = targetMouseY;
                } else {
                  mouseX += (targetMouseX - mouseX) * 0.16;
                  mouseY += (targetMouseY - mouseY) * 0.16;
                }
              }
          
              for (let i = 0; i < nodes.length; i++) {
                const node = nodes[i];
                let tx = node.ox;
                let ty = node.oy;
                let dist = 99999;
          
                if (mouseX !== -1000) {
                  const dx = node.ox - mouseX;
                  const dy = node.oy - mouseY;
                  const distSq = dx * dx + dy * dy;
          
                  if (distSq < rSq) {
                    dist = Math.sqrt(distSq) || 0.001;
                    const t = dist / radius;
                    const pull = (1.0 - t) * (1.0 - t) * 0.65;
                    
                    // Warp towards cursor
                    let rx = -dx * pull;
                    let ry = -dy * pull;
          
                    // Inside absolute center: gravity spiral swirl
                    if (dist < 40) {
                      const swirl = (1.0 - dist / 40) * 0.5;
                      const cosS = Math.cos(swirl);
                      const sinS = Math.sin(swirl);
                      const rxNew = rx * cosS - ry * sinS;
                      const ryNew = rx * sinS + ry * cosS;
                      rx = rxNew;
                      ry = ryNew;
                    }
          
                    tx = node.ox + rx;
                    ty = node.oy + ry;
                  }
                }
          
                const ax = (tx - node.x) * springK;
                const ay = (ty - node.y) * springK;
          
                node.vx = (node.vx + ax) * friction;
                node.vy = (node.vy + ay) * friction;
          
                node.x += node.vx;
                node.y += node.vy;
          
                node.disp = Math.hypot(node.x - node.ox, node.y - node.oy);
                node.mouseDist = dist;
              }
            }
          
            function draw() {
              ctx.fillStyle = '#08090b';
              ctx.fillRect(0, 0, canvas.width, canvas.height);
          
              if (mouseX !== -1000) {
                ctx.beginPath();
                const glow = ctx.createRadialGradient(mouseX, mouseY, 0, mouseX, mouseY, radius * 1.5);
                glow.addColorStop(0, 'rgba(168, 85, 247, 0.08)');
                glow.addColorStop(0.5, 'rgba(56, 189, 248, 0.02)');
                glow.addColorStop(1, 'rgba(0, 0, 0, 0)');
                ctx.fillStyle = glow;
                ctx.arc(mouseX, mouseY, radius * 1.5, 0, Math.PI * 2);
                ctx.fill();
              }
          
              ctx.textAlign = 'center';
              ctx.textBaseline = 'middle';
          
              const normalFont = 'bold 12px "JetBrains Mono", "Fira Code", monospace';
              const warpedFont = 'bold 14px "JetBrains Mono", "Fira Code", monospace';
          
              for (let i = 0; i < nodes.length; i++) {
                const node = nodes[i];
                
                if (node.disp < 0.1 && (mouseX === -1000 || node.mouseDist > radius)) {
                  ctx.font = normalFont;
                  ctx.fillStyle = 'rgba(148, 163, 184, 0.22)';
                  ctx.fillText(node.char, node.ox, node.oy);
                } else {
                  const dist = node.mouseDist;
                  
                  if (dist < radius) {
                    const t = 1.0 - (dist / radius);
                    
                    ctx.save();
                    ctx.translate(node.x, node.y);
                    
                    const angle = (node.vx + node.vy) * 0.035;
                    ctx.rotate(angle);
                    
                    const scale = 1.0 + t * 0.55;
                    ctx.scale(scale, scale);
                    
                    if (dist < 35) {
                      ctx.fillStyle = '#ffffff';
                      ctx.shadowColor = '#e879f9';
                      ctx.shadowBlur = 8;
                      ctx.font = warpedFont;
                    } else if (dist < 75) {
                      ctx.fillStyle = 'rgba(168, 85, 247, 0.95)';
                      ctx.shadowBlur = 0;
                      ctx.font = warpedFont;
                    } else {
                      ctx.fillStyle = 'rgba(56, 189, 248, 0.75)';
                      ctx.shadowBlur = 0;
                      ctx.font = normalFont;
                    }
                    
                    ctx.fillText(node.char, 0, 0);
                    ctx.restore();
                  } else {
                    ctx.font = normalFont;
                    const snapProgress = Math.min(node.disp / 30, 1.0);
                    const r = Math.floor(148 + snapProgress * (56 - 148));
                    const g = Math.floor(163 + snapProgress * (189 - 163));
                    const b = Math.floor(184 + snapProgress * (248 - 184));
                    const alpha = 0.2 + snapProgress * 0.25;
                    
                    ctx.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
                    ctx.fillText(node.char, node.x, node.y);
                  }
                }
              }
            }
          
            function render() {
              if (!canvas.isConnected) {
                cleanup();
                return;
              }
          
              update();
              draw();
              requestAnimationFrame(render);
            }
          
            requestAnimationFrame(render);
          })();
          </script>
        ` }}
      />
    </div>
  );
}

Raw CSS Stylesheet Snippet

.semantic-lens-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #08090c;
  overflow: hidden;
}
#canvas-semantic-warp-lens {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}