├── .gitignore ├── LICENSE ├── README.md ├── appleidanimation.swiftpm ├── .swiftpm │ ├── playgrounds │ │ ├── DocumentThumbnail.plist │ │ └── DocumentThumbnail.png │ └── xcode │ │ └── package.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── ContentView.swift ├── MyApp.swift └── Package.swift └── assets ├── output.mp4 ├── output.png ├── output_square.mov ├── source.mov └── source.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 An Trinh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apple ID Animation 2 | 3 | Recreating the animation on https://appleid.apple.com using SwiftUI. 4 | 5 | ### Result 6 | 7 | https://user-images.githubusercontent.com/16542463/181802356-7f755f5e-230a-4b16-a986-695e7a7669d3.mov 8 | 9 | ### Comparison 10 | 11 | Result | Reference 12 | --|-- 13 | | 14 | 15 | ### Reference 16 | 17 | https://user-images.githubusercontent.com/16542463/181802881-d1e38ad7-c8be-4f2c-9fe2-1702b6326e38.mov 18 | 19 | Source: https://appleid.apple.com 20 | -------------------------------------------------------------------------------- /appleidanimation.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DocumentThumbnailConfiguration 6 | 7 | accentColorHash 8 | 9 | ukeIsiaqjcLm3HQki7n2GM+oyVngwmwUe+SPaDmgsIg= 10 | 11 | appIconHash 12 | 13 | n5EWH0NDPkmm3m22gNefYBWfLkrJFyYhoShGQoFYRAs= 14 | 15 | thumbnailIsPrerendered 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /appleidanimation.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atrinh0/appleid-animation/fbb9eb6a536a3a881f5ebc0bc1aa3020dbe0b977/appleidanimation.swiftpm/.swiftpm/playgrounds/DocumentThumbnail.png -------------------------------------------------------------------------------- /appleidanimation.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /appleidanimation.swiftpm/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /appleidanimation.swiftpm/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | // Recreating the animation on https://appleid.apple.com using SwiftUI 4 | 5 | struct ContentView: View { 6 | var body: some View { 7 | ZStack { 8 | grayBackground 9 | animatingDots 10 | appleLogo 11 | } 12 | } 13 | 14 | private var grayBackground: some View { 15 | Color(white: 248/255) 16 | .edgesIgnoringSafeArea(.all) 17 | } 18 | 19 | private var animatingDots: some View { 20 | ZStack { 21 | gradientBackground 22 | .mask { 23 | ZStack { 24 | AnimatedDots(delay: 0) 25 | AnimatedDots(delay: 0.25) 26 | .scaleEffect(0.88) 27 | .rotationEffect(.degrees(360/48)) 28 | AnimatedDots(delay: 0.5) 29 | .scaleEffect(0.88 * 0.88) 30 | AnimatedDots(delay: 0.75) 31 | .scaleEffect(0.88 * 0.88 * 0.88) 32 | .rotationEffect(.degrees(360/48)) 33 | } 34 | } 35 | } 36 | } 37 | 38 | private var gradientBackground: some View { 39 | AngularGradient(colors: [.cyan, .indigo, .pink, .orange, .cyan], center: .center, startAngle: .degrees(-45), endAngle: .degrees(360-45)) 40 | } 41 | 42 | private var appleLogo: some View { 43 | Image(systemName: "applelogo") 44 | .foregroundColor(.black) 45 | .font(Font.system(size: 90)) 46 | .offset(y: -9) 47 | } 48 | } 49 | 50 | struct AnimatedDots: View { 51 | let delay: Double 52 | 53 | @State private var animating = false 54 | @State private var rotation = 0.0 55 | private let timer = Timer.publish(every: 3, on: .main, in: .common).autoconnect() 56 | 57 | var body: some View { 58 | dots 59 | .opacity(animating ? 1 : 0) 60 | .scaleEffect(animating ? 1 : 0.5) 61 | .rotationEffect(.degrees(rotation)) 62 | .onAppear { 63 | fadeIn() 64 | } 65 | .onReceive(timer) { _ in 66 | if animating { 67 | fadeOut() 68 | } else { 69 | fadeIn() 70 | } 71 | } 72 | } 73 | 74 | private func fadeIn() { 75 | withAnimation(.easeInOut(duration: 1.8).delay(delay)) { 76 | rotation += 60 77 | animating = true 78 | } 79 | } 80 | 81 | private func fadeOut() { 82 | withAnimation(.easeInOut(duration: 1.8).delay(1 - delay)) { 83 | rotation += 60 84 | animating = false 85 | } 86 | } 87 | 88 | private var dots: some View { 89 | Canvas { context, size in 90 | let dimensionOffset = size.width/2 91 | let image = context.resolve(Image(systemName: "circle.fill")) 92 | var currentPoint = CGPoint(x: dimensionOffset - image.size.width/2, y: 0) 93 | 94 | for _ in 0...24 { 95 | currentPoint = currentPoint.applying(.init(rotationAngle: Angle.degrees(360/24).radians)) 96 | context.draw(image, at: CGPoint(x: currentPoint.x + dimensionOffset, y: currentPoint.y + dimensionOffset)) 97 | } 98 | } 99 | .frame(width: 390, height: 390) 100 | .rotationEffect(.degrees(360/48)) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /appleidanimation.swiftpm/MyApp.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct MyApp: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | ContentView() 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /appleidanimation.swiftpm/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.6 2 | 3 | // WARNING: 4 | // This file is automatically generated. 5 | // Do not edit it by hand because the contents will be replaced. 6 | 7 | import PackageDescription 8 | import AppleProductTypes 9 | 10 | let package = Package( 11 | name: "appleidanimation", 12 | platforms: [ 13 | .iOS("15.2") 14 | ], 15 | products: [ 16 | .iOSApplication( 17 | name: "appleidanimation", 18 | targets: ["AppModule"], 19 | bundleIdentifier: "com.atrinh.appleidanimation", 20 | teamIdentifier: "6DRH5697SN", 21 | displayVersion: "1.0", 22 | bundleVersion: "1", 23 | appIcon: .placeholder(icon: .leaf), 24 | accentColor: .presetColor(.green), 25 | supportedDeviceFamilies: [ 26 | .pad, 27 | .phone 28 | ], 29 | supportedInterfaceOrientations: [ 30 | .portrait, 31 | .landscapeRight, 32 | .landscapeLeft, 33 | .portraitUpsideDown(.when(deviceFamilies: [.pad])) 34 | ] 35 | ) 36 | ], 37 | targets: [ 38 | .executableTarget( 39 | name: "AppModule", 40 | path: "." 41 | ) 42 | ] 43 | ) -------------------------------------------------------------------------------- /assets/output.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atrinh0/appleid-animation/fbb9eb6a536a3a881f5ebc0bc1aa3020dbe0b977/assets/output.mp4 -------------------------------------------------------------------------------- /assets/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atrinh0/appleid-animation/fbb9eb6a536a3a881f5ebc0bc1aa3020dbe0b977/assets/output.png -------------------------------------------------------------------------------- /assets/output_square.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atrinh0/appleid-animation/fbb9eb6a536a3a881f5ebc0bc1aa3020dbe0b977/assets/output_square.mov -------------------------------------------------------------------------------- /assets/source.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atrinh0/appleid-animation/fbb9eb6a536a3a881f5ebc0bc1aa3020dbe0b977/assets/source.mov -------------------------------------------------------------------------------- /assets/source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atrinh0/appleid-animation/fbb9eb6a536a3a881f5ebc0bc1aa3020dbe0b977/assets/source.png --------------------------------------------------------------------------------