Iso Search
IllustrationsIsometric illustration — a magnifying glass floating over a grid of opportunity dots, with a radar sweep inside the lens. Themeable accent via `brand`; animation stills under reduced-motion.
components/ui/iso-search.tsx
"use client";
import { motion, useReducedMotion } from "motion/react";
/**
* Isometric illustration — a magnifying glass floating over a grid of
* opportunity dots on a shared floor tile, with a radar sweep inside the lens.
* The accent is themeable via `brand`; animation stills under reduced-motion.
*/
export function IsoSearch({
brand = "#FF4701",
className,
}: {
brand?: string;
className?: string;
}) {
const reduce = useReducedMotion();
const dots = [
{ x: 70, y: 150, hit: false },
{ x: 92, y: 162, hit: true },
{ x: 118, y: 152, hit: false },
{ x: 138, y: 168, hit: true },
{ x: 80, y: 174, hit: false },
{ x: 110, y: 180, hit: true },
];
return (
<svg viewBox="0 0 200 210" className={className} style={{ ["--brand" as string]: brand }}>
<IsoPlatform />
{dots.map((d, i) => (
<motion.circle
key={i}
cx={d.x}
cy={d.y}
r={d.hit ? 2.4 : 1.6}
fill={d.hit ? "var(--brand)" : "rgba(0,0,0,0.35)"}
initial={{ opacity: 0.4 }}
animate={reduce ? undefined : { opacity: d.hit ? [0.4, 1, 0.4] : [0.3, 0.6, 0.3] }}
transition={{ duration: 2.4, repeat: Infinity, delay: i * 0.25, ease: "easeInOut" }}
/>
))}
<motion.g
initial={{ y: 0 }}
animate={reduce ? undefined : { y: [-2, 2, -2] }}
transition={{ duration: 3.4, repeat: Infinity, ease: "easeInOut" }}
>
<ellipse cx="108" cy="158" rx="14" ry="4" fill="rgba(0,0,0,0.08)" />
<circle cx="108" cy="118" r="20" fill="rgba(255,255,255,0.9)" stroke="var(--brand)" strokeWidth="2.4" />
<motion.path
d="M108 118 L108 98 A20 20 0 0 1 128 118 Z"
fill="rgba(217,119,6,0.18)"
initial={{ rotate: 0 }}
animate={reduce ? undefined : { rotate: 360 }}
transition={{ duration: 3.6, repeat: Infinity, ease: "linear" }}
style={{ transformOrigin: "108px 118px" }}
/>
<line x1="123" y1="133" x2="138" y2="148" stroke="var(--brand)" strokeWidth="3.2" strokeLinecap="round" />
</motion.g>
</svg>
);
}
/** Shared isometric floor tile — keeps the diorama on a consistent plane. */
function IsoPlatform() {
return (
<g>
<path
d="M100 138 L168 168 L100 198 L32 168 Z"
fill="rgba(217,119,6,0.05)"
stroke="rgba(217,119,6,0.18)"
strokeWidth="0.8"
/>
<path
d="M100 138 L168 168 M100 138 L32 168 M100 198 L32 168 M100 198 L168 168"
stroke="rgba(0,0,0,0.05)"
strokeWidth="0.6"
/>
{[0.25, 0.5, 0.75].map((t) => (
<g key={t} stroke="rgba(0,0,0,0.05)" strokeWidth="0.5">
<line x1={100 - 68 * t} y1={138 + 30 * t} x2={168 - 68 * t} y2={168 + 30 * t} />
<line x1={100 + 68 * t} y1={138 + 30 * t} x2={32 + 68 * t} y2={168 + 30 * t} />
</g>
))}
</g>
);
}Installation
Terminal
npx shadcn@latest add https://ui.saumyarex.xyz/r/iso-search.json1. Install dependencies
Terminal
npm install motion2. Copy the source into your project
components/ui/iso-search.tsx
"use client";
import { motion, useReducedMotion } from "motion/react";
/**
* Isometric illustration — a magnifying glass floating over a grid of
* opportunity dots on a shared floor tile, with a radar sweep inside the lens.
* The accent is themeable via `brand`; animation stills under reduced-motion.
*/
export function IsoSearch({
brand = "#FF4701",
className,
}: {
brand?: string;
className?: string;
}) {
const reduce = useReducedMotion();
const dots = [
{ x: 70, y: 150, hit: false },
{ x: 92, y: 162, hit: true },
{ x: 118, y: 152, hit: false },
{ x: 138, y: 168, hit: true },
{ x: 80, y: 174, hit: false },
{ x: 110, y: 180, hit: true },
];
return (
<svg viewBox="0 0 200 210" className={className} style={{ ["--brand" as string]: brand }}>
<IsoPlatform />
{dots.map((d, i) => (
<motion.circle
key={i}
cx={d.x}
cy={d.y}
r={d.hit ? 2.4 : 1.6}
fill={d.hit ? "var(--brand)" : "rgba(0,0,0,0.35)"}
initial={{ opacity: 0.4 }}
animate={reduce ? undefined : { opacity: d.hit ? [0.4, 1, 0.4] : [0.3, 0.6, 0.3] }}
transition={{ duration: 2.4, repeat: Infinity, delay: i * 0.25, ease: "easeInOut" }}
/>
))}
<motion.g
initial={{ y: 0 }}
animate={reduce ? undefined : { y: [-2, 2, -2] }}
transition={{ duration: 3.4, repeat: Infinity, ease: "easeInOut" }}
>
<ellipse cx="108" cy="158" rx="14" ry="4" fill="rgba(0,0,0,0.08)" />
<circle cx="108" cy="118" r="20" fill="rgba(255,255,255,0.9)" stroke="var(--brand)" strokeWidth="2.4" />
<motion.path
d="M108 118 L108 98 A20 20 0 0 1 128 118 Z"
fill="rgba(217,119,6,0.18)"
initial={{ rotate: 0 }}
animate={reduce ? undefined : { rotate: 360 }}
transition={{ duration: 3.6, repeat: Infinity, ease: "linear" }}
style={{ transformOrigin: "108px 118px" }}
/>
<line x1="123" y1="133" x2="138" y2="148" stroke="var(--brand)" strokeWidth="3.2" strokeLinecap="round" />
</motion.g>
</svg>
);
}
/** Shared isometric floor tile — keeps the diorama on a consistent plane. */
function IsoPlatform() {
return (
<g>
<path
d="M100 138 L168 168 L100 198 L32 168 Z"
fill="rgba(217,119,6,0.05)"
stroke="rgba(217,119,6,0.18)"
strokeWidth="0.8"
/>
<path
d="M100 138 L168 168 M100 138 L32 168 M100 198 L32 168 M100 198 L168 168"
stroke="rgba(0,0,0,0.05)"
strokeWidth="0.6"
/>
{[0.25, 0.5, 0.75].map((t) => (
<g key={t} stroke="rgba(0,0,0,0.05)" strokeWidth="0.5">
<line x1={100 - 68 * t} y1={138 + 30 * t} x2={168 - 68 * t} y2={168 + 30 * t} />
<line x1={100 + 68 * t} y1={138 + 30 * t} x2={32 + 68 * t} y2={168 + 30 * t} />
</g>
))}
</g>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
brand | string | "#FF4701" | Accent color; drives `--brand` inside the SVG. |
className | string | — | Classes for the <svg> (size it here). |
Dependencies
motion