useTime
useTime
returns a Svelte readable store that updates once per animation frame with elapsed milliseconds since the store was created.
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const rotate = derived(time, (t) => ((t % 4000) / 4000) * 360)
</script>
<div style="transform: rotate({$rotate}deg)">
Rotating content
</div>
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const rotate = derived(time, (t) => ((t % 4000) / 4000) * 360)
</script>
<div style="transform: rotate({$rotate}deg)">
Rotating content
</div>
Usage
The store value represents elapsed milliseconds, making it perfect for time-based animations that need to stay in sync with Svelte’s reactivity system.
<script lang="ts">
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
// Create derived values for smooth animations
const x = derived(time, (t) => Math.sin(t / 1000) * 100)
const y = derived(time, (t) => Math.cos(t / 1000) * 100)
const rotate = derived(time, (t) => (t / 10) % 360)
</script>
<div style="transform: translate({$x}px, {$y}px) rotate({$rotate}deg)">
Animated content
</div>
<script lang="ts">
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
// Create derived values for smooth animations
const x = derived(time, (t) => Math.sin(t / 1000) * 100)
const y = derived(time, (t) => Math.cos(t / 1000) * 100)
const rotate = derived(time, (t) => (t / 10) % 360)
</script>
<div style="transform: translate({$x}px, {$y}px) rotate({$rotate}deg)">
Animated content
</div>
Shared timelines
Pass an id
string to share the same timeline across multiple components. All calls with the same id
will receive the same store instance, keeping animations perfectly synchronized.
Note: Within a single component, you can simply reuse the same store reference. The
id
parameter is specifically useful for synchronizing animations across different components that don’t share scope.
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
// This component will sync with any other component using 'global'
const time = useTime('global')
const rotation = derived(time, (t) => (t / 20) % 360)
</script>
<div style="transform: rotate({$rotation}deg)">
Synced animation
</div>
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
// This component will sync with any other component using 'global'
const time = useTime('global')
const rotation = derived(time, (t) => (t / 20) % 360)
</script>
<div style="transform: rotate({$rotation}deg)">
Synced animation
</div>
Multiple components synchronized
<!-- ComponentA.svelte -->
<script>
import { useTime } from '@humanspeak/svelte-motion'
const time = useTime('shared-timeline')
</script>
<div>Time: {$time}ms</div>
<!-- ComponentB.svelte -->
<script>
import { useTime } from '@humanspeak/svelte-motion'
const time = useTime('shared-timeline')
</script>
<div>Same time: {$time}ms</div>
<!-- ComponentA.svelte -->
<script>
import { useTime } from '@humanspeak/svelte-motion'
const time = useTime('shared-timeline')
</script>
<div>Time: {$time}ms</div>
<!-- ComponentB.svelte -->
<script>
import { useTime } from '@humanspeak/svelte-motion'
const time = useTime('shared-timeline')
</script>
<div>Same time: {$time}ms</div>
Even though these are separate components, they both receive updates from the same timeline by using the same id
, ensuring perfect synchronization.
Synced timeline example
Here’s a complete example demonstrating the power of shared timelines. Notice how two separate useTime()
calls with the same id
return synchronized stores:
<script lang="ts">
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
// Two separate useTime calls with the same id
const time = useTime('synced-timeline')
const time2 = useTime('synced-timeline')
// Create animations from DIFFERENT store references
const rotate1 = derived(time, (t) => (t / 10) % 360)
const rotate2 = derived(time2, (t) => (t / 10) % 360)
const scale1 = derived(time, (t) => 1 + Math.sin(t / 800) * 0.2)
const scale2 = derived(time2, (t) => 1 + Math.sin(t / 800) * 0.2)
const hue = derived(time, (t) => (t / 30) % 360)
</script>
<div>
<!-- Element A uses 'time' -->
<div style="
transform: rotate({$rotate1}deg) scale({$scale1});
background: linear-gradient(135deg, hsl({$hue}, 70%, 60%), hsl({$hue + 30}, 70%, 50%));
">
A
</div>
<!-- Element B uses 'time2' -->
<div style="
transform: rotate({$rotate2}deg) scale({$scale2});
background: linear-gradient(135deg, hsl({$hue + 120}, 70%, 60%), hsl({$hue + 150}, 70%, 50%));
">
B
</div>
<!-- Proof they're synchronized -->
<div>
time: {$time}ms = time2: {$time2}ms
</div>
</div>
<script lang="ts">
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
// Two separate useTime calls with the same id
const time = useTime('synced-timeline')
const time2 = useTime('synced-timeline')
// Create animations from DIFFERENT store references
const rotate1 = derived(time, (t) => (t / 10) % 360)
const rotate2 = derived(time2, (t) => (t / 10) % 360)
const scale1 = derived(time, (t) => 1 + Math.sin(t / 800) * 0.2)
const scale2 = derived(time2, (t) => 1 + Math.sin(t / 800) * 0.2)
const hue = derived(time, (t) => (t / 30) % 360)
</script>
<div>
<!-- Element A uses 'time' -->
<div style="
transform: rotate({$rotate1}deg) scale({$scale1});
background: linear-gradient(135deg, hsl({$hue}, 70%, 60%), hsl({$hue + 30}, 70%, 50%));
">
A
</div>
<!-- Element B uses 'time2' -->
<div style="
transform: rotate({$rotate2}deg) scale({$scale2});
background: linear-gradient(135deg, hsl({$hue + 120}, 70%, 60%), hsl({$hue + 150}, 70%, 50%));
">
B
</div>
<!-- Proof they're synchronized -->
<div>
time: {$time}ms = time2: {$time2}ms
</div>
</div>
Both elements animate in perfect synchronization even though they use different store references (time
and time2
). The magic happens because both useTime('synced-timeline')
calls return the same underlying timeline. Watch the values display - they’re always identical! This is especially powerful when these elements live in separate components - the id
parameter ensures they all stay in sync without prop drilling or context.
How it works
useTime
leverages Svelte’s reactive store system:
- Creates a readable store that updates via
requestAnimationFrame
- Returns elapsed milliseconds since the store was created
- With an
id
, returns a shared store instance for synchronization - Automatically cleans up animation frames when all subscribers unsubscribe
Store lifecycle
<script>
const time = useTime()
// Subscribe explicitly
const unsubscribe = time.subscribe(value => {
console.log('Elapsed time:', value, 'ms')
})
// Or use $ prefix for automatic subscription
$: console.log('Current time:', $time)
</script>
<script>
const time = useTime()
// Subscribe explicitly
const unsubscribe = time.subscribe(value => {
console.log('Elapsed time:', value, 'ms')
})
// Or use $ prefix for automatic subscription
$: console.log('Current time:', $time)
</script>
The store automatically starts updating when you subscribe and stops when all subscriptions are removed.
Performance
useTime
is optimized for smooth animations:
- Frame-perfect: Updates at display refresh rate (typically 60 FPS)
- Efficient: Single
requestAnimationFrame
loop per unique timeline - Shared resources: Multiple subscribers share the same animation frame
- Auto-cleanup: Cancels frames when no subscribers remain
Common patterns
Smooth rotation
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const degrees = derived(time, (t) => (t / 10) % 360)
</script>
<div style="transform: rotate({$degrees}deg)">
↻
</div>
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const degrees = derived(time, (t) => (t / 10) % 360)
</script>
<div style="transform: rotate({$degrees}deg)">
↻
</div>
Oscillating scale
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const scale = derived(time, (t) => 1 + Math.sin(t / 500) * 0.2)
</script>
<div style="transform: scale({$scale})">
Pulsing
</div>
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const scale = derived(time, (t) => 1 + Math.sin(t / 500) * 0.2)
</script>
<div style="transform: scale({$scale})">
Pulsing
</div>
Color cycling
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const hue = derived(time, (t) => (t / 20) % 360)
</script>
<div style="background: hsl({$hue}, 70%, 50%)">
Rainbow
</div>
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime()
const hue = derived(time, (t) => (t / 20) % 360)
</script>
<div style="background: hsl({$hue}, 70%, 50%)">
Rainbow
</div>
Multiple synchronized animations
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime('sync')
const x = derived(time, (t) => Math.sin(t / 1000) * 50)
const y = derived(time, (t) => Math.cos(t / 800) * 30)
const rotate = derived(time, (t) => (t / 15) % 360)
const scale = derived(time, (t) => 1 + Math.sin(t / 600) * 0.1)
</script>
<div style="transform: translate({$x}px, {$y}px) rotate({$rotate}deg) scale({$scale})">
Complex animation
</div>
<script>
import { useTime } from '@humanspeak/svelte-motion'
import { derived } from 'svelte/store'
const time = useTime('sync')
const x = derived(time, (t) => Math.sin(t / 1000) * 50)
const y = derived(time, (t) => Math.cos(t / 800) * 30)
const rotate = derived(time, (t) => (t / 15) % 360)
const scale = derived(time, (t) => 1 + Math.sin(t / 600) * 0.1)
</script>
<div style="transform: translate({$x}px, {$y}px) rotate({$rotate}deg) scale({$scale})">
Complex animation
</div>
API Reference
Parameters
- id
string
(optional) - Timeline identifier for sharing across components
Returns
A Svelte Readable<number>
store containing elapsed milliseconds since creation.
Methods
The returned store implements Svelte’s Readable
interface:
interface Readable<T> {
subscribe(run: (value: T) => void): () => void
}
interface Readable<T> {
subscribe(run: (value: T) => void): () => void
}
When to use
Use useTime
when you need:
- Reactive time values - Integrate time into Svelte’s reactive system
- Store-based animations - Derive multiple animated values from one timeline
- Cross-component synchronization - Keep separate components in sync with shared timeline
id
- Declarative time - Use
$time
syntax for clean, reactive code
For direct DOM manipulation or frame-by-frame control, consider useAnimationFrame instead.
Comparison with useAnimationFrame
Feature | useTime | useAnimationFrame |
---|---|---|
Returns | Reactive store | Cleanup function |
Usage | Declarative with $ | Imperative callback |
Integration | Svelte stores | Direct DOM |
Derived values | Easy with derived() | Manual calculation |
Synchronization | Built-in with id | Manual coordination |
See also
- useAnimationFrame - For direct frame control
- useTransform - For mapping and transforming values
- useSpring - For spring-based animations
- Examples - See useTime in action
Based on Motion’s useTime API.