Svelte Fundamentals

Countdown Timer

Svelte Fundamentals

Check out a free preview of the full Svelte Fundamentals course

The "Countdown Timer" Lesson is part of the full, Svelte Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Rich demonstrates creating a countdown timer component and displaying the countdown above the grid. Animating the countdown with the time remaining is also covered in this segment.


Transcript from the "Countdown Timer" Lesson

>> So there's a little bit more game UI that we need to add before we start making it look nice, and that is the countdown timer. You'll recall from when we were looking at this before we have a countdown timer at the top of the page. And you can see that the bar is gradually dwindling, just makes the game a little bit more fun and challenging if you're up against the clock.

So we're gonna create one more component, that's a countdown.svelte component. And inside there we're gonna take a remaining prop. And a duration prop. That should be a lowercase number. We need to add lang=ts, so that we know that we did them in TypeScript. Div class ="countdown", and then inside that we're gonna have the pause button.

And the bar representing the duration, and inside that bar, the bar representing the remaining time. So the container element is gonna be another flex element. The duration bar is gonna fill the remainder of the space after the button has been added. And then the remaining bar is just going to be a position absolute bar inside that.

All right, let's add this component to the page so that we can start seeing it, and that way, we'll get immediate feedback as we're writing the styles. This will help us figure out what needs to go where. So go back to our page, and then inside Game.svelte in that top info container, I'll add the countdown.

Remaining let's just do LevelDuration for now, and then duration is also levelDuration. And you can see that it's imported that component and put it at the top of our script block. So the first thing we wanna do is get a pause icon that we can put inside our button.

What I usually do is I just Google material design icons. There's a site called Pictogrammers, which I find pretty reliable if I'm looking for an icon. If I go in here and I search for pause, then I'll see this pause icon here. That looks like basically what we want.

So I'm gonna open that, click on the code symbol here. It's gonna copy a bunch of SVG for me, and I'm just gonna put that inside the button like that. We can't see it yet because we need to make the button big enough. Okay, now we can see the SVG inside the button.

This duration div needs to have a width and height so that we can see it. We'll give that a height of 1em and a background color of yellow so that we can see it. And you can see that it is now appearing at the top of the info block.

But we wanna make everything inside here center aligned. Like that, and as is our custom, we'll give it a gap of, let's say, 1. We're gonna make the button have a square aspect ratio as well, like that, and we're gonna make the contents of the button fill this container.

Okay, that's starting to look how we want it to look. Except that I think we're gonna want to give the SVG a different fill color. I'm gonna make this slightly tidier so that I can see what's going on. At the end of the path, we don't have a fill attribute, so we're gonna create one.

And for now we'll just put in 999 or something like that. At this point I think we can get rid of the purple background on the info boxes because we don't need that anymore, we can see what's happening. Just gonna get rid of that, and I'm gonna do the same for the grid container, we don't need that anymore.

I think it's starting to look a little bit nicer. Back over in Countdown.svelte, we'll give the duration a background of, let's say, 999 again, a little later CCC. And then the remaining can have a height of 100%, and a background that's gonna be a little bit darker so that we can see it, let's do 999.

Right now it's not visible because we haven't given it a width. We're gonna need to control the width based on how much time is remaining in our countdown. One easy way to do this is to use a CSS custom property. So that's style=, and then do say, --p, it's gonna be remaining as a proportion of the duration.

And then we can base the width on that value, To a count of 100% times the p that we just parsed in. Right and now because the remaining defaults to the duration of the level, it's filling the entire range that we've got. So let's actually make the countdown work.

Inside game.svelte, we're gonna use request animation frame, we'll create a countdown function. And inside here, we'll have some request animation frame logic that is gonna assign to some new values that we're gonna create. So let remaining number is gonna begin as level.duration, that duration is also level.duration. But when we start the countdown, We're gonna decrement remaining until it hits zero.

First thing we need to do is find out what the current time is. Start = And then we can store how much time is remaining at each point once the countdown activates, remaining_at_start= remaining. Then we'll create our request animation frame loop, just call it loop like that.

And the first thing we're gonna do is call itself, Inside request animation frame. And we're gonna assign to remaining and do remaining_at_start minus whatever time has elapsed since the start. Now, you might look at that code that I just wrote and think, well, why not just subtract a 60th of a second each time?

It's a valid question. The reality is that you can't guarantee that requestAnimationFrame is gonna be called exactly 60 times a second. So you can get a kind of a drift when you do things that way. It's better if you can deal with deltas from absolute times, you'll get a more accurate result that way.

So if remaining is less than 0 or less than or equal to 0, I guess I should put, well, then at that point the game has been lost. So we'll just add a note to ourselves TODO the game has been lost. And we wanna stop the countdown at that point.

So let's add another value. We'll do let playing, Is false. And then inside our loop, if the game is no longer playing, then, We returned before calling the requestAnimationFrame, and then down here playing becomes false once we run out of time. I'm gonna add an onMount here, that just calls countdown.

And then we're gonna pass that remaining value into our countdown component. It's not working because I forgot to call the loop function. VS Code has helpfully grayed it out so that I can see that it's not being used anywhere. If I now run that, hopefully, we're going to start seeing that countdown bar to dwindle.

Yes, we are, okay. So things are starting to come together.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now