A comprehensive Svelte utility package for managing intervals with reactive durations, synchronization, and advanced control features. This package provides convenient classes and functions for creating and controlling setInterval
operations with full reactivity support.
Features:
$state
clearInterval
when durations change or components unmountimmediate: true
)npm install svelte-interval-rune
<script>
import { Interval } from 'svelte-interval-rune';
const timer = new Interval(1000);
</script>
<p>Time: {timer.current.toLocaleTimeString()}</p>
<p>Ticks: {timer.tickCount}</p>
<script>
import { Interval } from 'svelte-interval-rune';
// Lazy (default) - starts when accessed
const lazyTimer = new Interval(1000);
// Immediate - starts right away
const immediateTimer = new Interval(1000, { immediate: true });
</script>
<p>Lazy: {lazyTimer.current.toLocaleTimeString()}</p>
<p>Immediate: {immediateTimer.current.toLocaleTimeString()}</p>
<script>
import { Interval } from 'svelte-interval-rune';
let speed = $state(1000);
const timer = new Interval(() => speed);
</script>
<p>Duration: {timer.duration}ms | Ticks: {timer.tickCount}</p>
<button onclick={() => speed = 500}>Fast</button>
<button onclick={() => speed = 2000}>Slow</button>
<script>
import { Interval } from 'svelte-interval-rune';
const timer = new Interval(1000);
</script>
<p>Ticks: {timer.tickCount} | Status: {timer.isActive ? 'Running' : timer.isStopped ? 'Stopped' : 'Paused'}</p>
<button onclick={() => timer.pause()}>Pause</button>
<button onclick={() => timer.resume()}>Resume</button>
<button onclick={() => timer.resume(true)}>Resume Immediate</button>
<button onclick={() => timer.stop()}>Stop</button>
Key Differences:
Use LimitedInterval
when you need an interval that automatically stops after a specific number of ticks.
<script>
import { LimitedInterval } from 'svelte-interval-rune';
const timer = new LimitedInterval(500, 10); // 500ms interval, stops after 10 ticks
</script>
<p>Ticks: {timer.tickCount} / {timer.maxTicks}</p>
<p>Remaining: {timer.remainingTicks}</p>
<p>Completed: {timer.isCompleted}</p>
<button onclick={() => timer.reset()}>Reset</button>
<input type="number" bind:value={timer.maxTicks} min="1" />
maxTicks
reset()
to continue from current tick countmaxTicks
at runtimeremainingTicks
isCompleted
statusThe sync()
function allows multiple intervals to tick together at the pace of the fastest interval.
<script>
import { Interval, LimitedInterval, sync } from 'svelte-interval-rune';
const timer1 = new Interval(1000); // 1 second
const timer2 = new Interval(500); // 500ms (will be leader - fastest)
const timer3 = new LimitedInterval(750, 5); // 750ms, 5 ticks max
const controller = sync(timer1, timer2, timer3);
</script>
<p>Leader: {controller.leader.duration}ms | Sync: {controller.isSynced ? 'On' : 'Off'}</p>
<p>Timer1: {timer1.tickCount} | Timer2: {timer2.tickCount} | Timer3: {timer3.tickCount}</p>
<button onclick={() => controller.enable()}>Enable Sync</button>
<button onclick={() => controller.disable()}>Disable Sync</button>
<script>
import { Interval, LimitedInterval, sync } from 'svelte-interval-rune';
const fast = new Interval(100); // Fast timer
const limited = new LimitedInterval(200, 3); // Limited interval
const controller = sync(fast, limited);
</script>
<p>Fast: {fast.tickCount} | Limited: {limited.tickCount}/{limited.maxTicks}</p>
<p>Leader: {controller.leader.duration}ms | Completed: {limited.isCompleted}</p>
<button onclick={() => controller.enable()}>Start Sync</button>
<button onclick={() => limited.reset()}>Reset Limited</button>
new Interval(duration: number | (() => number), options?: IntervalOptions)
Parameters:
duration
- Static number or reactive function returning interval duration in millisecondsoptions.immediate?
- If true
, starts interval immediately. Default: false
current: Date
- Gets current time and auto-starts intervalduration: number
- Gets or sets the interval durationisActive: boolean
- Whether the interval is currently active (not paused/stopped)isStopped: boolean
- Whether the interval has been completely stoppedtickCount: number
- Number of times the interval has fired (auto-starts interval)pause(): void
- Pauses the interval (can be resumed)resume(immediate?: boolean): void
- Resumes the interval, optionally with immediate tickstop(): void
- Completely stops and cleans up the interval[Symbol.dispose](): void
- Automatic cleanup (works with using
)Extends Interval
with automatic completion after N ticks.
new LimitedInterval(duration: number | (() => number), maxTicks: number, options?: IntervalOptions)
Additional Parameters:
maxTicks
- Number of ticks before auto-completionmaxTicks: number
- Gets or sets the maximum tick limitisCompleted: boolean
- Whether the interval has reached its tick limitremainingTicks: number
- Number of ticks remaining before completionreset(): void
- Resets completion state and resumes from current tick countfunction sync(...intervals: Interval[]): SyncController;
Parameters:
...intervals
- One or more Interval or LimitedInterval instances to synchronizeinterface SyncController {
enable(): void; // Start synchronization
disable(): void; // Stop synchronization and restore individual timing
isSynced: boolean; // Whether sync is currently active
leader: Interval; // The fastest interval driving synchronization
}
interface IntervalOptions {
immediate?: boolean; // Start interval immediately on construction
}
<script>
import { Interval } from 'svelte-interval-rune';
let duration = $state(1000);
let timer = $state(new Interval(() => duration));
function resetTimer() {
timer.stop();
timer = new Interval(() => duration);
}
</script>
<p>Ticks: {timer.tickCount} | Duration: {duration}ms</p>
<button onclick={() => duration = 500}>Fast</button>
<button onclick={() => resetTimer()}>Reset</button>
<script>
import { LimitedInterval } from 'svelte-interval-rune';
let countdown = new LimitedInterval(1000, 10); // 10 second countdown
</script>
<p>{countdown.isCompleted ? 'Time\'s Up!' : `${countdown.remainingTicks}s left`}</p>
<button onclick={() => countdown.current}>Start</button>
<button onclick={() => countdown.reset()}>Reset</button>
current
or tickCount
is first accessed (unless immediate: true
)