feat: add AR phone illustration component

This commit is contained in:
rajun 2026-10-09 15:11:51 +05:30
parent bcb0b5fc69
commit c9c36d5fa3

View File

@ -0,0 +1,129 @@
import { Armchair } from '~/components/auth/armchair';
export function ArIllustration() {
return (
<svg
viewBox="0 0 400 460"
className="h-auto w-full max-w-[380px] animate-[float_7s_ease-in-out_infinite] drop-shadow-[0_30px_60px_rgba(0,0,0,0.6)]"
role="img"
aria-label="An armchair placed in a room through a phone camera in augmented reality"
>
<defs>
<linearGradient id="chair-back" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stopColor="#fb923c" />
<stop offset="55%" stopColor="#c2410c" />
<stop offset="100%" stopColor="#7c2d12" />
</linearGradient>
<linearGradient id="chair-back-inner" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#f97316" />
<stop offset="100%" stopColor="#9a3412" />
</linearGradient>
<linearGradient id="chair-cushion" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#fdba74" />
<stop offset="100%" stopColor="#ea580c" />
</linearGradient>
<linearGradient id="chair-base" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#c2410c" />
<stop offset="100%" stopColor="#7c2d12" />
</linearGradient>
<linearGradient id="chair-arm-left" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stopColor="#9a3412" />
<stop offset="100%" stopColor="#ea580c" />
</linearGradient>
<linearGradient id="chair-arm-right" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stopColor="#f97316" />
<stop offset="100%" stopColor="#9a3412" />
</linearGradient>
<linearGradient id="chair-wood" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#92582f" />
<stop offset="100%" stopColor="#3f2412" />
</linearGradient>
<linearGradient id="ar-screen" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#161616" />
<stop offset="60%" stopColor="#1a1511" />
<stop offset="100%" stopColor="#221810" />
</linearGradient>
<linearGradient id="ar-grid-fade" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="white" stopOpacity="0" />
<stop offset="100%" stopColor="white" stopOpacity="1" />
</linearGradient>
<mask id="ar-grid-mask">
<rect x="0" y="200" width="400" height="200" fill="url(#ar-grid-fade)" />
</mask>
<clipPath id="ar-screen-clip">
<rect x="118" y="38" width="164" height="364" rx="24" />
</clipPath>
<radialGradient id="ar-glow" cx="50%" cy="50%" r="50%">
<stop offset="0%" stopColor="#f97316" stopOpacity="0.3" />
<stop offset="100%" stopColor="#f97316" stopOpacity="0" />
</radialGradient>
<filter id="ar-blur" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="5" />
</filter>
</defs>
{/* Phone body */}
<rect x="108" y="28" width="184" height="384" rx="32" fill="#0b0b0b" stroke="#2a2a2a" strokeWidth="2" />
<rect x="118" y="38" width="164" height="364" rx="24" fill="url(#ar-screen)" />
<g clipPath="url(#ar-screen-clip)">
{/* Wall / floor horizon */}
<rect x="118" y="38" width="164" height="176" fill="white" opacity="0.015" />
{/* Perspective floor seen through the camera */}
<g stroke="#f97316" strokeOpacity="0.3" strokeWidth="1" mask="url(#ar-grid-mask)">
{[240, 262, 290, 326, 372].map((y) => (
<line key={y} x1="100" y1={y} x2="300" y2={y} />
))}
{[-260, -170, -90, -30, 30, 90, 170, 260].map((dx) => (
<line key={dx} x1="200" y1="214" x2={200 + dx} y2="420" />
))}
</g>
<ellipse cx="200" cy="320" rx="96" ry="40" fill="url(#ar-glow)" />
{/* Placement reticle */}
<ellipse cx="200" cy="320" rx="76" ry="19" fill="none" stroke="#f97316" strokeWidth="1.5" strokeDasharray="5 5">
<animate attributeName="stroke-dashoffset" from="0" to="-20" dur="2s" repeatCount="indefinite" />
</ellipse>
<ellipse cx="200" cy="320" rx="60" ry="15" fill="#f97316" fillOpacity="0.12">
<animate attributeName="fill-opacity" values="0.18;0.05;0.18" dur="2.4s" repeatCount="indefinite" />
</ellipse>
<Armchair />
{/* Camera scan brackets */}
<g fill="none" stroke="white" strokeOpacity="0.55" strokeWidth="2" strokeLinecap="round">
<path d="M136 152 V138 H150" />
<path d="M264 152 V138 H250" />
<path d="M136 342 V356 H150" />
<path d="M264 342 V356 H250" />
</g>
{/* AR badge */}
<rect x="180" y="62" width="40" height="18" rx="9" fill="#f97316" fillOpacity="0.15" stroke="#f97316" strokeOpacity="0.6" />
<text x="200" y="74.5" textAnchor="middle" fontSize="9" fontWeight="700" letterSpacing="1" fill="#fb923c" fontFamily="Inter, sans-serif">AR</text>
{/* Shutter */}
<circle cx="200" cy="380" r="12" fill="none" stroke="white" strokeOpacity="0.4" strokeWidth="2" />
<circle cx="200" cy="380" r="8" fill="#f97316" />
</g>
{/* Notch */}
<rect x="172" y="46" width="56" height="8" rx="4" fill="#0b0b0b" />
{/* Floating particles */}
{[
{ cx: 70, cy: 120, r: 3, d: '3s' },
{ cx: 330, cy: 90, r: 2, d: '4s' },
{ cx: 345, cy: 260, r: 3, d: '3.6s' },
{ cx: 55, cy: 300, r: 2, d: '4.4s' },
{ cx: 95, cy: 210, r: 1.5, d: '2.8s' },
].map((p) => (
<circle key={`${p.cx}-${p.cy}`} cx={p.cx} cy={p.cy} r={p.r} fill="#f97316">
<animate attributeName="opacity" values="0.15;0.8;0.15" dur={p.d} repeatCount="indefinite" />
</circle>
))}
</svg>
);
}