Focused Breathing

title: focused breathing - A CSS animation to help with meditation and focused breathing exercises
published: false
description: My submission to the DigitalOcean App Platform Hackathon!
tags: dohackathon, css, javascript

What I built

My Digital Ocean / DEV hackathon submission is *focused breathing* a CSS animation to help with meditation and focused breathing exercises.

Category Submission

Program for the People

App Link or


Screenshot of focused breathing in its default state.

The timing of the animation (expanding, holding and contracting) is set to 8 seconds by default. The timing can be changed using the input field.

Here’s a video of the app in action.


focused breathing includes a circle div that expands for 2 seconds, holds it’s shape for 2 seconds, then contracts to its original size for 4 seconds. The breathing exercise involves inhaling through the nose as the circle expands. Holding the breath. Then exhaling through the mouth as the circle contracts.

Link to Source Code

Permissive License



(What made you decide to build this particular app? What inspired you?)

I recently learned about focused breathing exercises as part of a meditation or calming routine. I kept forgetting the timing of how long to inhale, hold long do I hold, etc. So, I decided to make a little app to help me with the pacing.

I’ve been having fun experimenting with CSS animations and thought this would be an excellent opportunity to learn about the animation property, transitions, and @keyframes.

How I built it

(How did you utilize DigitalOcean’s App Platform? Did you learn something new along the way? Pick up a new skill?)

I built *focused breathing* in two parts. The first version was an experiment with CSS animations and @keyframes. I wanted to see if I could achieve the transitions and cadence I wanted with only HTML and CSS. It was possible! No Javascript was needed for the original version, which can be found on CodePen.

For the second part, I wanted to see if I change the duration of the animation (which is in the CSS file) based on input from the user. I know I could get input values from the HTML file with Javascript, but could I pass those updated variables back to the CSS and render it to the page. It turns out this was possible too!

Here’s how I approached building parts one and two and what I learned along the way.

Part One – HTML & CSS

Before I started coding, I was helpful for me to write down high-level steps of the focused breathing technique I had been taught.

It goes like this.

  • Inhale through the nose
  • Hold the breath
  • Exhale through the mouth for 4 seconds

The amount of time to inhale of hold the breath may not matter, but to make it easier from a coding perspective, 2 seconds to inhale and 2 seconds to hold a breath seemed reasonable.

Visually, there would be a small to medium sized circle that would expand, cueing you inhale and contract when it was time to exhale.

Visualizing the Animation

Using @keyframes was the best want to handle the expanding and contracting of the circle so that I control the timing and pacing of each step. With @keyframes the stops or offsets range between 0% and 100%. The beginning or start of the animation would be 0% stop and the end would be 100%. Or, any number in between.

I’ve worked with @keyframes on other projects and had a difficult time visualizing what code I needed to write to achieve what I visualized in my mind.

It makes sense to map out what I wanted to happen like a timeline. A line segment with two endpoints could represent the timeline of the animation. The left endpoint would be the beginning of the animation cycle and the right, the end.

Some quick labels, notes and visuals and I have a timeline that looks like this.

Translating the Timeline to @keyframes

Looking at the timeline above, it may look like we need 8 or 4 steps in the animation, but this is not the case. Each offset point in a @keyframe animation is a point where properties can be changed from their original values.

The circle starts small, then it’s changed to be larger than it was originally, then it holds that size, then it shrinks down to the size it was originally and the animation starts over. The @keyframe only needs 2 offset points (at the 25% and 50% marks) and the original styling of the circle handles the starting (and ending) visuals.

Similar to grouping other CSS attributes, multiple properties and offsets can be set at one time within the @keyframe declaration.

@keyframes breath {
 25%, 50% {
    background-color: lightpink;
    width: 200px;
    height: 200px;
    border-radius: 100px;

And, to make it a bit easier on ourselves, let’s divide the line into 8 even parts (1 part for each second of the animation).

The timing of the changes and width and height of the circle meant that I couldn’t

The expanding and contracting of the circle can be handled with @keyframes.

Part 2 – Javascript

For the second part of this project, I wanted to add some customization. To start, I wanted to see if I could change the duration of the animation—which was 8s to start—to another value. Building an input field was straight forward, but how could that value get updated in the animation property?

In doing some Googling, I was reminded that CSS variables could be accessed and updated with Javascript using getComputedStyle and getPropertyValue. I was already using CSS variables for colors and sizes, so created a new one for timing.

:root {
    --timing: 8s;

And updated my animation property to include that variable (var(–timing)) instead of the hardcoded value (8s)

animation: breath var(--timing) ease infinite none running

Visually, nothing changed, which meant it worked! I could double check the value of --timing by running the following in the Console.

getComputedStyle(document.documentElement).getPropertyValue('--timing') // 8s

And I could change it with the following and see the animation speed up dramtically.'--timing', '1s');

Then, by adding an input field onto the page, I could grab the value of that input, pass it into .setProperty and update the CSS.

Wrap Up

Overall, I learned a lot about @keyframes with this project! Drawing out what I had in mind made coding go smoother with less trial and error.

Looking back at this project, I tried for the first time, or became more comfortable with:

  • CSS Grid (centering things, amiright?)
  • CSS Animations (the animation and @keyframes property)
  • Manipulating CSS variables with Javascript ( getComputedStyle and getPropertyValue)
  • Continuous deployment (yikes to manually copy and pasting files like I usually do)

For future enhancements, some thoughts are:

  • The ability to change other variables (hold time is longer, shorter, etc)
  • The ability to start and stop (or, incorporate a timer for 5 mins of focused breathing, etc)
  • Sounds or music so accompany to indicate when you breath in, breath out, etc.
  • A detailed tutorial on how to build your own focused breathing animation/app from scratch
  • CSS grid
  • CSS Variables
  • CSS Animations
  • Javascript
  • Redirect


  • Did not need to use setTimout for initial build Can change CSS variable with javascript

Additional Resources/Info

Leave a comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.