Loading video...

Video Failed to Load

Go Home

I've started meditating again after a while. 🧘🏼 So, naturally, I wanted to copy the Headspace app's loading animation. I spent way too much time rebuilding it using #SwiftUI. I tried improving it (original in comment), let me know Headspace if you need access to the code.😇

93,359 views • 1 year ago •via X (Twitter)

36 Comments

Stefan's profile picture
Stefan1 year ago

Here's the original animation:

Qodo (formerly Codium)'s profile picture
Qodo (formerly Codium)1 year ago

Make code reviews seamless with Qodo Merge. Directly implement changes to PRs, apply modifications from review comments, and fine-tune updates using intelligent suggestions. Let Qodo Merge learn and adapt to your team’s best practices for better results.

Sean Kelly's profile picture
Sean Kelly1 year ago

Had a go at the animation part, here's my effort: import SwiftUI struct ContentView: View { @State private var scale: CGFloat = 0.1 @State private var yOffset: CGFloat = 0 @State private var breatheIn = false @State private var animationStarted = false var body: some View { GeometryReader { geometry in ZStack { Color(UIColor.systemIndigo).ignoresSafeArea() ZStack { Circle() .fill( .frame(width: geometry.size.width * 0.8, height: geometry.size.width * 0.8) .scaleEffect(scale * (breatheIn ? 1.6 : 1.1)) FaceView(breatheIn: breatheIn) .frame(width: geometry.size.width * 0.4, height: geometry.size.width * 0.4) .offset(y: -geometry.size.height * 0.3) .scaleEffect(scale * (breatheIn ? 0.8 : 0.6)) } .offset(y: yOffset + (breatheIn ? -geometry.size.height * 0.1 : 0)) } .onAppear { withAnimation(.easeInOut(duration: 2)) { scale = 1.5 yOffset = geometry.size.height * 0.45 } DispatchQueue.main.asyncAfter(deadline: .now() + 2) { animationStarted = true withAnimation(Animation.easeInOut(duration: 4).repeatForever(autoreverses: true)) { breatheIn.toggle() } } } } } } struct FaceView: View { var breatheIn: Bool let strokeWidth: CGFloat = 0.08 var body: some View { GeometryReader { geometry in ZStack { // Eyes EyeView() .stroke( style: StrokeStyle(lineWidth: geometry.size.width * strokeWidth, lineCap: .round, lineJoin: .round)) .frame(width: geometry.size.width, height: geometry.size.height * 0.4) .position(x: geometry.size.width / 2, y: geometry.size.height * 0.4) // Smile SmileShape(progress: breatheIn ? 1 : 0) .stroke( style: StrokeStyle(lineWidth: geometry.size.width * strokeWidth, lineCap: .round, lineJoin: .round)) .frame(width: geometry.size.width, height: geometry.size.height * 0.6) .position(x: geometry.size.width / 2, y: geometry.size.height * 0.7) .animation(.easeInOut(duration: 4).repeatForever(autoreverses: true), value: breatheIn) } } } } struct EyeView: Shape { func path(in rect: CGRect) -> Path { var path = Path() let width = rect.width let height = rect.height // Left eye path.move(to: CGPoint(x: width * 0.2, y: height * 0.5)) path.addQuadCurve( to: CGPoint(x: width * 0.4, y: height * 0.5), control: CGPoint(x: width * 0.3, y: height * 0.3) ) // Right eye path.move(to: CGPoint(x: width * 0.6, y: height * 0.5)) path.addQuadCurve( to: CGPoint(x: width * 0.8, y: height * 0.5), control: CGPoint(x: width * 0.7, y: height * 0.3) ) return path } } struct SmileShape: Shape { var progress: CGFloat var animatableData: CGFloat { get { progress } set { progress = newValue } } func path(in rect: CGRect) -> Path { var path = Path() let width = rect.width let height = rect.height let smileWidth = 0.4 + (0.6 * progress) let smileHeight = 0.55 + (0.55 * progress) let startX = width * ((1 - smileWidth) / 2) let endX = width * (1 - (1 - smileWidth) / 2) path.move(to: CGPoint(x: startX, y: height * 0.6)) path.addQuadCurve( to: CGPoint(x: endX, y: height * 0.6), control: CGPoint(x: width * 0.5, y: height * smileHeight) ) return path } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

Anum 's profile picture
Anum 1 year ago

@Headspace Wow thats pretty neat!

Stefan's profile picture
Stefan1 year ago

@Headspace Thanks a lot. Really enjoyed building out that one.

Simon Auer's profile picture
Simon Auer1 year ago

@Headspace Looking very good though! Nice work!

Stefan's profile picture
Stefan1 year ago

@Headspace Thank you, Simon!

Satyendra Mourya's profile picture
Satyendra Mourya1 year ago

@Headspace I sometimes wonder how I can do this on the web.

Stefan's profile picture
Stefan1 year ago

@Headspace That is an excellent question. In my experience, keyframe animations can get you quite far: But for these more complex ones, I have achieved great results with @framer motion:

Lusine Magauzyan's profile picture
Lusine Magauzyan1 year ago

@Headspace Looks amazing! Not Headspace but wud love access to the code 😅

Patrick Freyer's profile picture
Patrick Freyer1 year ago

@Headspace Did you use Xcode 16 yet? Curious whether those AI features did any good to your project!

Stefan's profile picture
Stefan1 year ago

@Headspace I did use Xcode 16, but not any of the AI features. I'm not sure why the Autocomplete doesn't work for me yet. Maybe I missed activating it at some point. 😇 But to answer your question, there was no AI help for this one.

Beatriz Cunha's profile picture
Beatriz Cunha1 year ago

@Headspace really good! I just felt the breathing is a bit too fast, but maybe it's the video speed. great stuff!

Stefan's profile picture
Stefan1 year ago

@Headspace Thank you! Yes, you might be right. It could indeed be a bit slower. The problem is that you're never finished with an animation like this. So, at some point, I just needed to say, "It's good enough," and at least share it. But good catch!

aboghaly 🇵🇸's profile picture
aboghaly 🇵🇸1 year ago

@Headspace 👏👏👏👏👏

Amir Dev's profile picture
Amir Dev1 year ago

@Headspace That animation looks awesome! Did rebuilding it in SwiftUI end up being more relaxing than meditating? 😄

Stefan's profile picture
Stefan1 year ago

@startdustdev @Headspace Haha, thank you. And the creation of the animation was not more relaxing than a meditation. However, I can get into a very focused state while working on things like that, which probably has a therapeutic effect to some degree. :)

Pencil's profile picture
Pencil1 year ago

I would love to see the code, pls

wophb's profile picture
wophb1 year ago

@Headspace That's awesome, Stefan! Your dedication to meditating and then taking the time to rebuild the animation in SwiftUI is really inspiring. Would love to see more of your creative projects!

Stefan's profile picture
Stefan1 year ago

@Headspace Thank you! I will share more of the experiments I'm building and even plan to turn some of them into tutorials to share the techniques used for others to learn. :)

Khoa 🔥's profile picture
Khoa 🔥1 year ago

@Headspace It looks great Stefan

Stefan's profile picture
Stefan1 year ago

@Headspace Thanks Khoa, I definitely went the extra mile here. But it was just so much fun. :)

Marco Peñuelas 🔴's profile picture
Marco Peñuelas 🔴1 year ago

@Headspace Genial !

Piotr 💻's profile picture
Piotr 💻1 year ago

@Headspace Great animation 🔥

Jan Stehlík's profile picture
Jan Stehlík1 year ago

@Headspace I'm not headspace but I need the code 😀

Harshvardhan Trivedi's profile picture
Harshvardhan Trivedi1 year ago

@Headspace Looks Awesome!

Kҽʋιɳ Sҽɾɾαɳσ's profile picture
Kҽʋιɳ Sҽɾɾαɳσ1 year ago

@Headspace Nice 🤩

Chris Wakefield 彡👾's profile picture
Chris Wakefield 彡👾1 year ago

@Headspace Wow! This is awesome!

Senior Ngenge's profile picture
Senior Ngenge1 year ago

@Headspace Where is the link to your SwiftUI course? 😂😂

Frank Junior's profile picture
Frank Junior1 year ago

@Headspace Please share the code to let usl learning the animation thank you

Piyush Pandey (PiYu)'s profile picture
Piyush Pandey (PiYu)1 year ago

@Headspace Looks Amazing @stefanjblos ... How can I do it in Android...

Salvador's profile picture
Salvador1 year ago

@Headspace Wonder if I could replicate it using react native reanimated 🤔

Abdullah Ajmal's profile picture
Abdullah Ajmal1 year ago

@Headspace Smoothhhh! 🔥

Alperen Sarışan's profile picture
Alperen Sarışan1 year ago

@Headspace Wow this is really nice. If I was one of the users, I’d create that account. Also thank you for sharing the code

brother ahmet's profile picture
brother ahmet1 year ago

@Headspace looks really nice!

Wilbur's profile picture
Wilbur1 year ago

@Headspace Love the animation

Related Videos