> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getsabo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Particles

> Particle background component.

* **Location**: `sabo/src/components/ui/particles.tsx`

<Frame>
  <div className="rounded-xl" style={{ overflow: "hidden", border: "1px solid #e5e7eb" }}>
    <iframe
      className="w-full"
      style={{ height: "180px", pointerEvents: "none" }}
      title="Particles"
      loading="lazy"
      scrolling="no"
      srcDoc={`<!doctype html><html><head><meta charset='utf-8'/><meta name='viewport' content='width=device-width,initial-scale=1'/><style>
body{margin:0;background:#ffffff}
canvas{display:block;width:100%;height:160px}
</style></head><body>
<canvas id='c'></canvas>
<script>
  const cv=document.getElementById('c'); const ctx=cv.getContext('2d'); function rs(){cv.width=cv.clientWidth*2; cv.height=160*2} rs();
  const P=80; const particles=[...Array(P)].map(()=>({x:Math.random()*cv.width,y:Math.random()*cv.height,vx:(Math.random()-0.5)*0.6,vy:(Math.random()-0.5)*0.6,r:1+Math.random()*2}));
  function step(){ctx.clearRect(0,0,cv.width,cv.height); ctx.fillStyle='#111827'; particles.forEach(p=>{p.x+=p.vx;p.y+=p.vy;if(p.x<0||p.x>cv.width)p.vx*=-1;if(p.y<0||p.y>cv.height)p.vy*=-1; ctx.globalAlpha=.6; ctx.beginPath(); ctx.arc(p.x,p.y,p.r,0,Math.PI*2); ctx.fill();}); requestAnimationFrame(step)} step();
  new ResizeObserver(rs).observe(cv);
</script>
</body></html>`}
    />
  </div>
</Frame>

## When to use

* Lightweight decorative particles behind hero or section headers.
* Keep density/contrast low; avoid interfering with text legibility.

## Usage

```tsx sabo/src/components/ui/particles.tsx theme={null}
import { Particles } from "@/components/ui/particles";

export function Example() {
  return (
    <div className="relative rounded-xl border p-8 overflow-hidden">
      <Particles className="absolute inset-0" quantity={80} color="#111827" />
      <div className="relative z-10">Content over particles</div>
    </div>
  );
}
```

## Key props

<ParamField path="quantity" type="number" default="100">
  How many particles to render.
</ParamField>

<ParamField path="color" type="string" default="#ffffff">
  Particle color (hex).
</ParamField>

<ParamField path="size" type="number" default="0.4">
  Base particle radius.
</ParamField>

<ParamField path="vx" type="number" default="0">
  Constant velocity offset on X axis.
</ParamField>

<ParamField path="vy" type="number" default="0">
  Constant velocity offset on Y axis.
</ParamField>

<ParamField path="staticity" type="number" default="50">
  Mouse interaction strength (lower = stronger attraction).
</ParamField>

<ParamField path="ease" type="number" default="50">
  Particle movement smoothness.
</ParamField>

<ParamField path="className" type="string">
  Additional CSS classes applied to the container div.
</ParamField>

## Styling tip

* Mount as an absolutely positioned layer; keep `pointer-events: none`.
* Test light/dark themes to ensure contrast is appropriate.
