THE VOID UI/UX design protocol and rules. Use whenever building, modifying, or reviewing any UI component, page, or layout in THE VOID app. Covers layout rules, visual effects, loading states, card styling, animations, and design constraints.
/images/foo.pngbackdrop-blur-xl, border border-white/10, bg-gradient-to-br with color-tinted gradientsrounded-2xlp-6 to p-10Floating radial gradient orbs behind content:
<motion.div
animate={{ scale: [1, 1.3, 1], opacity: [0.15, 0.25, 0.15] }}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
className="absolute top-1/4 left-1/4 w-[500px] h-[500px] rounded-full"
style={{ background: "radial-gradient(circle, rgba(6,182,212,0.3) 0%, transparent 70%)" }}
/>
Use cyan and purple as primary orb colors. Vary duration (8-12s) and delay for multiple orbs.
Always show skeleton loaders while data loads — never blank screens:
<div className="animate-pulse space-y-4">
<div className="h-8 bg-white/5 rounded-xl w-3/4" />
<div className="h-4 bg-white/5 rounded-lg w-1/2" />
<div className="h-32 bg-white/5 rounded-2xl" />
</div>
animate-pulse with bg-white/5 on dark backgrounds<div className="w-full h-1 bg-white/5 rounded-full overflow-hidden">
<motion.div
className="h-full bg-gradient-to-r from-cyan-500 to-purple-500 rounded-full"
initial={{ width: "0%" }}
animate={{ width: "100%" }}
transition={{ duration: 2, ease: "easeInOut" }}
/>
</div>
All sections use viewport-triggered animations:
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
>
<AnimatePresence mode="wait">
<motion.div
key={currentIndex}
initial={{ opacity: 0, x: 80 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -80 }}
transition={{ duration: 0.35, ease: "easeInOut" }}
>
When text sits on top of video or images:
className="drop-shadow-[0_2px_12px_rgba(0,0,0,0.8)]"
cyan-400, cyan-500)purple-400, purple-500, purple-600)bg-black, #0a0a0a)text-white, text-white/70, text-white/40, text-white/20)border-white/10bg-white/5 to bg-white/10font-display)font-bold or font-black, tracking-widetext-xs tracking-[0.3em] uppercase in accent colortext-sm or text-xs with reduced opacity<div className="relative rounded-2xl border border-white/10 bg-gradient-to-br from-{color}-500/20 via-{color}-600/10 to-transparent backdrop-blur-xl p-8">
backdrop-blur-xl, border-white/10, gradient backgroundTwo stacked <video> elements with crossfade:
playsInline, muted={true}, autoPlay for mobile compatibilitykey prop on each video forces React to create fresh elements on swap.catch(() => {}) on .play() for autoplay blocksfrom-cyan-500 to-purple-600), min-h-12, shadow-lgtext-white/80 font-medium with drop shadowsw-6 h-1.5), inactive = small circle (w-1.5 h-1.5)data-testid attributesEvery page follows:
Layout component with sticky header, hamburger nav, footer