Responsive Design
Make your Lumidot animations responsive by adjusting rows, cols, and scale based on screen size.Using CSS Media Queries
Adjust the loader appearance with CSS classes and media queries.import { Lumidot } from 'lumidot';
import './responsive.css';
function ResponsiveLoader() {
return (
<div className="responsive-container">
<Lumidot
variant="blue"
pattern="all"
rows={3}
cols={3}
className="responsive-loader"
/>
</div>
);
}
/* responsive.css */
.responsive-loader {
transform: scale(1);
}
/* Mobile */
@media (max-width: 640px) {
.responsive-loader {
transform: scale(0.8);
}
}
/* Tablet */
@media (min-width: 641px) and (max-width: 1024px) {
.responsive-loader {
transform: scale(1.2);
}
}
/* Desktop */
@media (min-width: 1025px) {
.responsive-loader {
transform: scale(1.5);
}
}
Using Window Size Hook
Dynamically adjust props based on viewport width.import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: typeof window !== 'undefined' ? window.innerWidth : 0,
});
useEffect(() => {
function handleResize() {
setWindowSize({ width: window.innerWidth });
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}
function AdaptiveLoader() {
const { width } = useWindowSize();
// Adjust based on screen size
const getLoaderProps = () => {
if (width < 640) {
// Mobile: smaller, simpler
return { rows: 2, cols: 2, scale: 1, glow: 6 };
} else if (width < 1024) {
// Tablet: medium
return { rows: 3, cols: 3, scale: 1.2, glow: 8 };
} else {
// Desktop: larger, more complex
return { rows: 4, cols: 4, scale: 1.5, glow: 10 };
}
};
const props = getLoaderProps();
return (
<div style={{ display: 'flex', justifyContent: 'center', padding: '2rem' }}>
<Lumidot
variant="emerald"
pattern="spiral"
{...props}
/>
</div>
);
}
Container Query Approach
Respond to container size instead of viewport.import { Lumidot } from 'lumidot';
import { useRef, useState, useEffect } from 'react';
function ContainerAdaptiveLoader() {
const containerRef = useRef(null);
const [containerWidth, setContainerWidth] = useState(0);
useEffect(() => {
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
setContainerWidth(entry.contentRect.width);
}
});
if (containerRef.current) {
observer.observe(containerRef.current);
}
return () => observer.disconnect();
}, []);
const getScale = () => {
if (containerWidth < 200) return 0.6;
if (containerWidth < 400) return 1;
if (containerWidth < 600) return 1.5;
return 2;
};
return (
<div ref={containerRef} style={{ width: '100%', textAlign: 'center' }}>
<Lumidot
variant="purple"
pattern="wave-lr"
rows={3}
cols={4}
scale={getScale()}
/>
</div>
);
}
Mobile-First Pattern Selection
Use simpler patterns on mobile, complex patterns on desktop.import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';
function PatternAdaptiveLoader() {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const checkMobile = () => setIsMobile(window.innerWidth < 768);
checkMobile();
window.addEventListener('resize', checkMobile);
return () => window.removeEventListener('resize', checkMobile);
}, []);
return (
<Lumidot
variant="cyan"
pattern={isMobile ? 'line-h-mid' : 'spiral'}
rows={isMobile ? 1 : 4}
cols={isMobile ? 5 : 4}
scale={isMobile ? 1 : 1.5}
glow={isMobile ? 6 : 10}
/>
);
}
Breakpoint-Based Component
Create a wrapper component with predefined breakpoints.import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';
type Breakpoint = 'mobile' | 'tablet' | 'desktop';
interface ResponsiveLumidotProps {
variant?: string;
pattern?: string;
mobile?: { rows: number; cols: number; scale: number; glow: number };
tablet?: { rows: number; cols: number; scale: number; glow: number };
desktop?: { rows: number; cols: number; scale: number; glow: number };
}
function ResponsiveLumidot({
variant = 'blue',
pattern = 'all',
mobile = { rows: 2, cols: 2, scale: 0.8, glow: 6 },
tablet = { rows: 3, cols: 3, scale: 1.2, glow: 8 },
desktop = { rows: 4, cols: 4, scale: 1.5, glow: 10 }
}: ResponsiveLumidotProps) {
const [breakpoint, setBreakpoint] = useState<Breakpoint>('desktop');
useEffect(() => {
const updateBreakpoint = () => {
const width = window.innerWidth;
if (width < 768) setBreakpoint('mobile');
else if (width < 1024) setBreakpoint('tablet');
else setBreakpoint('desktop');
};
updateBreakpoint();
window.addEventListener('resize', updateBreakpoint);
return () => window.removeEventListener('resize', updateBreakpoint);
}, []);
const props = breakpoint === 'mobile' ? mobile :
breakpoint === 'tablet' ? tablet : desktop;
return (
<Lumidot
variant={variant}
pattern={pattern}
{...props}
/>
);
}
// Usage
function App() {
return (
<ResponsiveLumidot
variant="indigo"
pattern="spiral"
mobile={{ rows: 2, cols: 2, scale: 0.7, glow: 4 }}
tablet={{ rows: 3, cols: 3, scale: 1, glow: 6 }}
desktop={{ rows: 5, cols: 5, scale: 2, glow: 12 }}
/>
);
}
Responsive Card Grid
Adapt loader size within a responsive grid layout.import { Lumidot } from 'lumidot';
function ResponsiveGrid() {
return (
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
gap: '1.5rem',
padding: '2rem'
}}>
{[1, 2, 3, 4, 5, 6].map(i => (
<div
key={i}
style={{
border: '1px solid #e5e7eb',
borderRadius: '8px',
padding: '2rem',
textAlign: 'center',
minHeight: '200px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<Lumidot
variant="teal"
pattern="frame-sync"
rows={3}
cols={3}
scale={1}
glow={8}
style={{ width: '100%', maxWidth: '80px' }}
/>
</div>
))}
</div>
);
}
Flexible Container
Make the loader fill its container responsively.import { Lumidot } from 'lumidot';
function FlexibleLoader() {
return (
<div style={{
width: '100%',
maxWidth: '600px',
margin: '0 auto',
padding: '2rem',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '300px',
background: '#f9fafb',
borderRadius: '12px'
}}>
<Lumidot
variant="violet"
pattern="all"
rows={4}
cols={4}
scale={1.5}
glow={10}
style={{
maxWidth: '100%',
height: 'auto'
}}
/>
</div>
);
}
Orientation-Aware Layout
Adjust rows and cols based on device orientation.import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';
function OrientationAwareLoader() {
const [isPortrait, setIsPortrait] = useState(true);
useEffect(() => {
const checkOrientation = () => {
setIsPortrait(window.innerHeight > window.innerWidth);
};
checkOrientation();
window.addEventListener('resize', checkOrientation);
window.addEventListener('orientationchange', checkOrientation);
return () => {
window.removeEventListener('resize', checkOrientation);
window.removeEventListener('orientationchange', checkOrientation);
};
}, []);
return (
<Lumidot
variant="orange"
pattern="wave-lr"
rows={isPortrait ? 5 : 3}
cols={isPortrait ? 3 : 5}
scale={1.2}
glow={8}
/>
);
}
Tips
- Start with
scaleadjustments before changingrowsandcols - Reduce
glowon mobile to improve performance - Use simpler patterns (fewer animated dots) on smaller screens
- Consider container size, not just viewport size
- Test on real devices to ensure smooth animations
- Use
prefers-reduced-motionfor accessibility (Lumidot handles this automatically)