Lumidot provides fine-grained control over animation timing and flow direction. You can adjust the speed of animations and control how wave effects propagate across the grid.
Duration Prop
The duration prop controls the animation cycle time in seconds.
Type: number
Default: 0.7
Unit: seconds
How it works
The duration affects the animation in two ways:
Wave delay calculation : Determines the delay between dots in wave patterns
CSS animation duration : Sets the --lumidot-duration CSS variable
From index.tsx:327-328:
'--lumidot-delay' : ` ${ on ? ( isSync ? 0 : waveDelay ( i , waveDir , duration , cols , rows )) : 0 } s` ,
'--lumidot-duration' : ` ${ duration } s` ,
Wave delay calculation
The waveDelay function calculates staggered delays for each dot based on its position. From index.tsx:191-224:
function waveDelay (
index : number ,
direction : LumidotDirection | LumidotWaveDirection ,
duration : number ,
cols : number ,
rows : number ,
) : number {
const col = index % cols ;
const row = Math . floor ( index / cols );
const step = duration / Math . max ( 5 , cols + rows - 2 );
const maxCol = cols - 1 ;
const maxRow = rows - 1 ;
switch ( direction ) {
case 'ltr' :
return ( col + row ) * step ;
case 'rtl' :
return ( maxCol - col + row ) * step ;
case 'ttb' :
return ( row + col ) * step ;
case 'btt' :
return ( maxRow - row + col ) * step ;
case 'lr' :
return col * step ;
case 'rl' :
return ( maxCol - col ) * step ;
case 'tb' :
return row * step ;
case 'bt' :
return ( maxRow - row ) * step ;
default :
return ( col + row ) * step ;
}
}
The step value is calculated as:
const step = duration / Math . max ( 5 , cols + rows - 2 );
This ensures the total wave animation completes within the specified duration.
Usage examples
Fast (0.4s)
Default (0.7s)
Slow (1.5s)
Very Slow (3s)
< Lumidot
pattern = "wave-lr"
variant = "cyan"
duration = { 0.4 }
/>
For subtle loaders, use longer durations (1.5-3s). For attention-grabbing animations, use shorter durations (0.3-0.5s).
Direction Prop
The direction prop controls the flow direction of wave animations.
Type: 'ltr' | 'rtl' | 'ttb' | 'btt'
Default: 'ltr'
Direction types
Value Direction Description ltrLeft to right Diagonal wave from top-left to bottom-right rtlRight to left Diagonal wave from top-right to bottom-left ttbTop to bottom Diagonal wave from top-left to bottom-right bttBottom to top Diagonal wave from bottom-left to top-right
Usage examples
Left to Right
Right to Left
Top to Bottom
Bottom to Top
< Lumidot
pattern = "all"
variant = "blue"
direction = "ltr"
/>
Wave Direction Patterns
Some patterns have built-in wave directions that override the direction prop. From index.tsx:44-49 and types.ts:44-49:
export const WAVE_DIRECTIONS = {
'wave-lr' : 'lr' ,
'wave-rl' : 'rl' ,
'wave-tb' : 'tb' ,
'wave-bt' : 'bt' ,
} as const ;
These patterns use specific wave directions:
Pure Horizontal (Left to Right)
Pure Horizontal (Right to Left)
Pure Vertical (Top to Bottom)
Pure Vertical (Bottom to Top)
< Lumidot
pattern = "wave-lr"
variant = "cyan"
rows = { 3 }
cols = { 7 }
/>
From index.tsx:275:
const waveDir = ( WAVE_DIRECTIONS as Partial < Record < LumidotPattern , LumidotWaveDirection >>)[ pattern ] ?? direction ;
For these patterns, the built-in wave direction takes precedence.
Synchronized Patterns
Some patterns animate all dots simultaneously without delays. From types.ts:42:
export const SYNC_PATTERNS = new Set < string >([ 'corners-sync' , 'frame-sync' ]);
For these patterns, duration still controls the animation speed, but all dots animate together:
< Lumidot
pattern = "corners-sync"
variant = "fuchsia"
duration = { 1 }
/>
< Lumidot
pattern = "frame-sync"
variant = "violet"
rows = { 5 }
cols = { 5 }
duration = { 0.5 }
/>
Sequence Patterns
Patterns with multiple frames (like spiral and corners-only) use a different timing mechanism. From index.tsx:281-287:
React . useEffect (() => {
if ( ! isSequence ) return ;
setFrame ( 0 );
if ( frames . length <= 1 || reduced ) return ;
const id = window . setInterval (() => setFrame (( prev ) => ( prev + 1 ) % frames . length ), 1250 );
return () => window . clearInterval ( id );
}, [ frames , reduced , isSequence ]);
These patterns cycle through frames every 1250ms (1.25 seconds), independent of the duration prop. The direction prop affects the order of frames:
// From index.tsx:165-167
case 'spiral' : {
const frames = spiralFrames ( rows , cols );
return rev ? [ ... frames].reverse() : frames ;
}
For sequence patterns like spiral, corners-only, and plus-hollow, the frame transition time is fixed at 1.25 seconds. The duration prop only affects the fade transition between frames (37ms fade-in, 250ms fade-out from index.tsx:276,318).
Combining Duration and Direction
You can create varied effects by combining different durations and directions:
// Fast diagonal wave
< Lumidot
pattern = "all"
variant = "cyan"
rows = { 5 }
cols = { 5 }
duration = { 0.4 }
direction = "ltr"
/>
// Slow reverse diagonal
< Lumidot
pattern = "all"
variant = "purple"
rows = { 5 }
cols = { 5 }
duration = { 2 }
direction = "btt"
/>
// Quick horizontal sweep
< Lumidot
pattern = "wave-lr"
variant = "emerald"
rows = { 3 }
cols = { 9 }
duration = { 0.5 }
/>
Accessibility
Lumidot respects the prefers-reduced-motion media query for sequence animations. From index.tsx:226-239:
function useReducedMotion ( enabled : boolean ) : boolean {
const [ reduced , setReduced ] = React . useState ( false );
React . useEffect (() => {
if ( ! enabled ) return ;
const mq = window . matchMedia ( '(prefers-reduced-motion: reduce) ;
setReduced ( mq . matches );
const handler = ( e : MediaQueryListEvent ) => setReduced ( e . matches );
mq . addEventListener ( 'change' , handler );
return () => mq . removeEventListener ( 'change' , handler );
}, [ enabled ]);
return reduced ;
}
When users have reduced motion enabled, sequence patterns show all dots simultaneously instead of transitioning between frames.
Next Steps View the complete API reference