Skip to content

Instantly share code, notes, and snippets.

@DarrenHurst
Created December 31, 2023 22:09
Show Gist options
  • Save DarrenHurst/aa7bf06e2e6fe058a2661d770570bacd to your computer and use it in GitHub Desktop.
Save DarrenHurst/aa7bf06e2e6fe058a2661d770570bacd to your computer and use it in GitHub Desktop.
TimeLine Tree
//
// tree2.swift
// Shop
//
// Created by Darren Hurst on 2023-12-23.
//
import Foundation
import SwiftUI
import SpriteKit
struct Tree2: View {
@State var animate: Bool = false
@State private var pathProgress = 0.0
var snowScene: SKScene {
let scene = SnowScene3()
scene.scaleMode = .resizeFill
scene.backgroundColor = .clear
return scene
}
var body: some View {
VStack {
Text("Happy New Year").foregroundColor(Color.white).offset(y:50)
Text("#SwiftUITree").foregroundColor(Color.white).offset(y:60)
TimelineView(.periodic(from: Date(), by: 1.0)) { timeline in
ZStack {
ScaledBezier(bezierPath: .treelights)
.trim(from:0.0 , to: animate ? 100.0 : 0.0 )
.stroke(LinearGradient(colors: [Color.random, Color.random, Color.random], startPoint: .leading, endPoint: .trailing), lineWidth:9)
.animation(.easeInOut(duration: 44), value: animate)
.frame(width: 80, height: 50)
.rotationEffect(.degrees(19))
.offset(x:40,y:-140)
.onAppear(){
self.animate.toggle()
}
}
// Slider(value: $pathProgress, in: 0.0...1.0)
// .padding()
.offset(y:-20)
}.frame(width: 300, height:600).opacity(0.7)
Text("2024").foregroundColor(Color.white).offset(y:-40).onTapGesture {
self.animate = false
}
}
.background(Color.blue.opacity(0.3))
.background(Color.black.opacity(0.8))
.ignoresSafeArea()
}
}
class SnowScene3: SKScene {
let snowEmitterNode = SKEmitterNode(fileNamed: "snow")
override func didMove(to view: SKView) {
let ball = SKShapeNode(path: ScaledBezier(bezierPath: .treelights).bezierPath.cgPath)
ball.lineWidth = 1
ball.fillColor = .blue
ball.strokeColor = .white
ball.glowWidth = 0.15
addChild(ball)
guard let snowEmitterNode = snowEmitterNode else { return }
snowEmitterNode.particleSize = CGSize(width: 50, height: 50)
snowEmitterNode.particleLifetime = 4
snowEmitterNode.particleLifetimeRange = 8
addChild(snowEmitterNode)
}
override func didChangeSize(_ oldSize: CGSize) {
guard let snowEmitterNode = snowEmitterNode else { return }
snowEmitterNode.particlePosition = CGPoint(x: size.width/2, y: size.height)
snowEmitterNode.particlePositionRange = CGVector(dx: size.width, dy: size.height)
}
}
extension Color {
static var random: Color {
return Color(
red: .random(in: 0.1...0.6),
green: .random(in: 0.7...0.9),
blue: .random(in: 0.5...1)
)
}
}
extension UIBezierPath {
static var treelights: UIBezierPath {
let path = UIBezierPath()
let x: Int = 8
let size: Double = -0.2
path.move(to: CGPoint(x: 0.2, y: 1))
for i in 1...x {
path.addCurve(to: CGPoint(x: -size, y: Double(i) + size ), controlPoint1: CGPoint( x: size, y: size + Double(i)),
controlPoint2: CGPoint(x: size + Double(i), y: -size))
}
return path
}
}
struct ScaledBezier: Shape {
let bezierPath: UIBezierPath
func path(in rect: CGRect) -> Path {
let path = Path(bezierPath.cgPath)
// Figure out how much bigger we need to make our path in order for it to fill the available space without clipping.
let multiplier = min(rect.width, rect.height)
// Create an affine transform that uses the multiplier for both dimensions equally.
let transform = CGAffineTransform(scaleX: multiplier, y: multiplier)
// Apply that scale and send back the result.
return path.applying(transform)
}
}
struct Tree2Preview: PreviewProvider {
static var previews: some View {
Tree2()
}
}
@DarrenHurst
Copy link
Author

Simulator.Screen.Recording.-.iPhone.14.Pro.-.2023-12-31.at.17.09.42.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment