VibeCoderzVibeCoderz
Telegram
All Prompts
Squares Background UI Preview
animationbackground

Squares Background

Анимированный фон из квадратов с направленным движением и эффектом при наведении. Настраиваемая скорость, цвет, направление. Для React.

by Zhou JasonLive Preview

Prompt

# Squares Background

You are given a task to integrate an existing React component in the codebase

~~~/README.md
# SquaresBackground

An animated grid background component consisting of moving squares. Supports directional movement, adjustable speed, customizable square sizes, and interactive hover effects.

## Dependencies
- `react`: ^18.x
- `lucide-react`: ^0.x

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `direction` | `'diagonal' \| 'up' \| 'right' \| 'down' \| 'left'` | `'right'` | The direction in which the grid squares move. |
| `speed` | `number` | `1` | The speed of the animation movement. |
| `borderColor` | `string` | `'#999'` | The stroke color for the square borders. |
| `squareSize` | `number` | `40` | The size of each square in pixels. |
| `hoverFillColor` | `string` | `'#222'` | The fill color of a square when it is hovered over. |

## Usage

```tsx
import { Squares } from '@/sd-components/2f6061b2-b0a8-4983-a973-36f6d0802fb9';

function MyPage() {
  return (
    <div style={{ width: '100%', height: '500px' }}>
      <Squares 
        speed={0.5} 
        squareSize={40}
        direction='diagonal'
        borderColor='#fff'
        hoverFillColor='#222'
      />
    </div>
  );
}
```
~~~

~~~/src/App.tsx
import React from 'react';
import { Squares } from './Component';

export default function App() {
  return (
    <div className="w-full h-screen bg-[#1A1A1B] overflow-hidden flex flex-col items-center justify-center p-20 relative">
      {/* Container with soft shadow for premium feel */}
      <div className="relative w-full h-full rounded-[40px] overflow-hidden shadow-[0_0_80px_rgba(0,0,0,0.2)] bg-black/20">
        <Squares 
          speed={0.5} 
          squareSize={40}
          direction="diagonal" 
          borderColor="#333"
          hoverFillColor="#444"
        />
        
        {/* Title Overlay */}
        <div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">
          <h1 className="text-white text-4xl font-medium tracking-tight mb-4 opacity-80 font-sans">
            Squares Animation
          </h1>
          <p className="text-white/40 text-sm font-normal tracking-wide">
            Minimalist Background Showcase
          </p>
        </div>

        {/* Reply Button Mockup */}
        <div className="absolute bottom-10 right-10">
          <button className="bg-white/10 hover:bg-white/20 text-white px-6 py-2 rounded-full backdrop-blur-md border border-white/10 transition-colors duration-300 pointer-events-auto">
            Reply
          </button>
        </div>
      </div>
    </div>
  );
}
~~~

~~~/package.json
{
  \"name\": \"@seedance/squares-background\",
  \"description\": \"Animated square grid background component\",
  \"dependencies\": {
    \"react\": \"^18.2.0\",
    \"react-dom\": \"^18.2.0\",
    \"lucide-react\": \"^0.344.0\"
  }
}
~~~

~~~/src/Component.tsx
/**
 * An animated grid background component consisting of moving squares.
 * Supports directional movement (up, down, left, right, diagonal), adjustable speed,
 * customizable square sizes, and interactive hover effects.
 */

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

type CanvasStrokeStyle = string | CanvasGradient | CanvasPattern;

interface GridOffset {
  x: number;
  y: number;
}

export interface SquaresProps {
  /**
   * Direction of the grid movement
   * @default 'right'
   */
  direction?: 'diagonal' | 'up' | 'right' | 'down' | 'left';
  /**
   * Movement speed of the squares
   * @default 1
   */
  speed?: number;
  /**
   * Color of the square borders
   * @default '#999'
   */
  borderColor?: CanvasStrokeStyle;
  /**
   * Size of each individual square in pixels
   * @default 40
   */
  squareSize?: number;
  /**
   * Background color when a square is hovered
   * @default '#222'
   */
  hoverFillColor?: CanvasStrokeStyle;
}

export const Squares: React.FC<SquaresProps> = ({
  direction = 'right',
  speed = 1,
  borderColor = '#999',
  squareSize = 40,
  hoverFillColor = '#222'
}) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const requestRef = useRef<number | null>(null);
  const numSquaresX = useRef<number>(0);
  const numSquaresY = useRef<number>(0);
  const gridOffset = useRef<GridOffset>({ x: 0, y: 0 });
  const hoveredSquareRef = useRef<GridOffset | null>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    const resizeCanvas = () => {
      canvas.width = canvas.offsetWidth;
      canvas.height = canvas.offsetHeight;
      numSquaresX.current = Math.ceil(canvas.width / squareSize) + 1;
      numSquaresY.current = Math.ceil(canvas.height / squareSize) + 1;
    };

    window.addEventListener('resize', resizeCanvas);
    resizeCanvas();

    const drawGrid = () => {
      if (!ctx) return;
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      const startX = Math.floor(gridOffset.current.x / squareSize) * squareSize;
      const startY = Math.floor(gridOffset.current.y / squareSize) * squareSize;

      ctx.lineWidth = 0.5;

      for (let x = startX; x < canvas.width + squareSize; x += squareSize) {
        for (let y = startY; y < canvas.height + squareSize; y += squareSize) {
          const squareX = x - (gridOffset.current.x % squareSize);
          const squareY = y - (gridOffset.current.y % squareSize);

          const gridX = Math.floor((x - startX) / squareSize);
          const gridY = Math.floor((y - startY) / squareSize);

          if (
            hoveredSquareRef.current &&
            gridX === hoveredSquareRef.current.x &&
            gridY === hoveredSquareRef.current.y
          ) {
            ctx.fillStyle = hoverFillColor;
            ctx.fillRect(squareX, squareY, squareSize, squareSize);
          }

          ctx.strokeStyle = borderColor;
          ctx.strokeRect(squareX, squareY, squareSize, squareSize);
        }
      }

      const gradient = ctx.createRadialGradient(
        canvas.width / 2,
        canvas.height / 2,
        0,
        canvas.width / 2,
        canvas.height / 2,
        Math.sqrt(Math.pow(canvas.width, 2) + Math.pow(canvas.height, 2)) / 2
      );
      gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
      gradient.addColorStop(1, 'rgba(6, 0, 16, 0.8)');
      ctx.fillStyle = gradient;
      ctx.fillRect(0, 0, canvas.width, canvas.height);
    };

    const updateAnimation = () => {
      const effectiveSpeed = Math.max(speed, 0.1);
      switch (direction) {
        case 'right':
          gridOffset.current.x = (gridOffset.current.x - effectiveSpeed + squareSize) % squareSize;
          break;
        case 'left':
          gridOffset.current.x = (gridOffset.current.x + effectiveSpeed + squareSize) % squareSize;
          break;
        case 'up':
          gridOffset.current.y = (gridOffset.current.y + effectiveSpeed + squareSize) % squareSize;
          break;
        case 'down':
          gridOffset.current.y = (gridOffset.current.y - effectiveSpeed + squareSize) % squareSize;
          break;
        case 'diagonal':
          gridOffset.current.x = (gridOffset.current.x - effectiveSpeed + squareSize) % squareSize;
          gridOffset.current.y = (gridOffset.current.y - effectiveSpeed + squareSize) % squareSize;
          break;
        default:
          break;
      }
      drawGrid();
      requestRef.current = requestAnimationFrame(updateAnimation);
    };

    const handleMouseMove = (event: MouseEvent) => {
      const rect = canvas.getBoundingClientRect();
      const mouseX = event.clientX - rect.left;
      const mouseY = event.clientY - rect.top;

      const hoveredSquareX = Math.floor((mouseX + (gridOffset.current.x % squareSize)) / squareSize);
      const hoveredSquareY = Math.floor((mouseY + (gridOffset.current.y % squareSize)) / squareSize);

      hoveredSquareRef.current = { x: hoveredSquareX, y: hoveredSquareY };
    };

    const handleMouseLeave = () => {
      hoveredSquareRef.current = null;
    };

    canvas.addEventListener('mousemove', handleMouseMove);
    canvas.addEventListener('mouseleave', handleMouseLeave);
    requestRef.current = requestAnimationFrame(updateAnimation);

    return () => {
      window.removeEventListener('resize', resizeCanvas);
      if (requestRef.current) cancelAnimationFrame(requestRef.current);
      canvas.removeEventListener('mousemove', handleMouseMove);
      canvas.removeEventListener('mouseleave', handleMouseLeave);
    };
  }, [direction, speed, borderColor, hoverFillColor, squareSize]);

  return (
    <canvas 
      ref={canvasRef} 
      className="w-full h-full border-none block bg-transparent"
    />
  );
};

export default Squares;
~~~

Implementation Guidelines

1. Analyze the component structure, styling, animation implementations
2. Review the component's arguments and state
3. Think through what is the best place to adopt this component/style into the design we are doing
4. Then adopt the component/design to our current system

Help me integrate this into my design
All Prompts