A vintage-style film countdown component for your Svelte 5 applications, built with runes.
start
, pause
, resume
, and reset
.onComplete
) or after each decrement (onEachCount
).loop
prop.Install svelte-film-countdown
using your preferred package manager:
npm install svelte-film-countdown
yarn add svelte-film-countdown
pnpm add svelte-film-countdown
bun add svelte-film-countdown
Import the FilmCountdown
component into your Svelte component:
<script>
import FilmCountdown from 'svelte-film-countdown';
let countdownInstance;
function handleComplete() {
alert('Countdown finished!');
}
function handleEachCount(currentCount) {
console.log('Current count:', currentCount);
}
function startCountdown() {
countdownInstance?.start();
}
function pauseCountdown() {
countdownInstance?.pause();
}
function resumeCountdown() {
countdownInstance?.resume();
}
function resetCountdown() {
countdownInstance?.reset();
}
</script>
<FilmCountdown
bind:this={countdownInstance}
initialCount={5}
countdownDuration={1000}
onComplete={handleComplete}
onEachCount={handleEachCount}
/>
<br />
<button on:click={startCountdown}>Start</button>
<button on:click={pauseCountdown}>Pause</button>
<button on:click={resumeCountdown}>Resume</button>
<button on:click={resetCountdown}>Reset</button>
Render the countdown with default settings:
<script>
import FilmCountdown from 'svelte-film-countdown';
</script>
<FilmCountdown />
Configure the starting number and the duration of each count:
<script>
import FilmCountdown from 'svelte-film-countdown';
</script>
<FilmCountdown initialCount={10} countdownDuration={500} />
Execute functions when the countdown finishes or after each count:
<script>
import FilmCountdown from 'svelte-film-countdown';
function handleComplete() {
console.log('Countdown finished!');
}
function handleEachCount(currentCount) {
console.log('Current count:', currentCount);
}
</script>
<FilmCountdown onComplete={handleComplete} onEachCount={handleEachCount} />
config
PropCustomize the visual appearance of the countdown through the config
prop:
<script>
import FilmCountdown from 'svelte-film-countdown';
</script>
<FilmCountdown
initialCount={3}
config={{
numberColor: "red",
numCircles: 4
}}
/>
Make the countdown restart automatically after reaching zero. Note that you need to manually trigger start()
to begin the countdown:
<script>
import FilmCountdown from 'svelte-film-countdown';
let countdownInstance;
function startLoopingCountdown() {
countdownInstance?.start();
}
</script>
<FilmCountdown bind:this={countdownInstance} loop={true} />
<button on:click={startLoopingCountdown}>Start Looping Countdown</button>
Prop Name | Type | Default Value | Description |
---|---|---|---|
initialCount |
number |
5 |
The number from which the countdown begins. |
countdownDuration |
number |
1000 |
The time in milliseconds for each count decrement. |
onComplete |
() => void |
() => {} |
A callback function that is executed when the countdown reaches 0. |
onEachCount |
(count: number) => void |
() => {} |
A callback function executed after each count, receiving the current count as an argument. |
config |
object |
{} |
An object containing properties to customize the visual aspects of the countdown. See the config details below. |
loop |
boolean |
false |
If true , the countdown will automatically reset to initialCount and stop at 0, ready to be started again. |
config
Object PropertiesProperty Name | Type | Default Value | Description |
---|---|---|---|
numberColor |
string |
'var(--countdown-number-color)' |
The color of the number displayed in the center of the countdown. |
numCircles |
number |
2 |
The number of concentric circles animating around the central number. |
circleRadius |
number |
64 |
The radius of the outermost circle in pixels. |
circleSpacing |
number |
8 |
The space in pixels between each concentric circle. |
strokeRatio |
number |
1 / 40 |
The ratio of the circle's radius that determines the thickness of the circle's stroke. |
canvasSize |
number |
256 |
The width and height of the SVG canvas (viewBox dimensions). The component will maintain a 16:9 aspect ratio. |
circleGradientStart |
string |
'var(--circle-gradient-start)' |
The starting color of the gradient applied to the circles. |
circleGradientMiddle |
string |
'var(--circle-gradient-middle)' |
The middle color of the gradient applied to the circles. |
circleGradientMiddleOpacity |
number |
0.8 |
The opacity of the middle color in the circle gradient. |
circleGradientEnd |
string |
'var(--circle-gradient-end)' |
The ending color of the gradient applied to the circles. |
To control the countdown programmatically, you need to bind a reference to the FilmCountdown
component using bind:this
.
start()
: Initiates the countdown sequence.pause()
: Temporarily halts the countdown.resume()
: Continues the countdown from the paused state.reset()
: Stops the countdown and resets it to the initialCount
.Customize the visual theme of the FilmCountdown
component by overriding these CSS variables in your global stylesheet or within a specific component's <style>
block.
:root {
--countdown-number-color: black;
--countdown-button-color: rgba(0, 0, 0, 0.8);
--countdown-button-text-color: white;
--film-hole-width: 20px;
--film-hole-rect-width: 8px;
--film-hole-rect-height: 12px;
--film-hole-y-top: 10px;
--film-hole-y-bottom: 22px;
--film-hole-color: black;
--sweeping-background-color: rgba(0, 0, 0, 0.15);
--circle-gradient-start: black;
--circle-gradient-middle: black;
--circle-gradient-middle-opacity: 0.8;
--circle-gradient-end: black;
--grid-line-color: rgba(255, 255, 255, 0.3);
--film-grain-opacity: 0.1;
--flicker-duration: 0.15s;
--vignette-strength: 0.4;
--center-vignette-strength: 0.15;
--scratch-color: rgba(255, 255, 255, 0.2);
--scratch-opacity: 0.15;
--number-font: monospace;
--number-text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
--film-grain-pattern: linear-gradient(to bottom, rgba(156, 163, 175, 0.05), transparent, rgba(156, 163, 175, 0.05));
}
Example of Applying a Theme:
<style>
:root {
--countdown-number-color: lightyellow;
--sweeping-background-color: rgba(100, 0, 0, 0.25);
--film-grain-opacity: 0.2;
}
</style>
<FilmCountdown />
Contributions are highly appreciated! If you find a bug, have an idea for an improvement, or want to add a new feature, please don't hesitate to open an issue or submit a pull request.