Skip to content

Instantly share code, notes, and snippets.

@SwiftyAlex
Created June 11, 2025 17:40
Show Gist options
  • Save SwiftyAlex/96362209d3edd845475e51ad96f81269 to your computer and use it in GitHub Desktop.
Save SwiftyAlex/96362209d3edd845475e51ad96f81269 to your computer and use it in GitHub Desktop.
Lava!
//
// Lava.swift
// coffeeai
//
// Created by Alex Logan on 11/06/2025.
//
import SwiftUI
struct Circle: Identifiable {
let id = UUID()
var position: CGPoint
var velocity: CGVector
var size: CGFloat
var color: Color
}
struct Lava: View {
@State private var circles: [Circle] = []
@State private var screenSize: CGSize = .zero
@State private var lastUpdate: Date?
@Namespace private var namespace
var body: some View {
GlassEffectContainer {
GeometryReader { geometry in
TimelineView(.animation(minimumInterval: 1.0/30.0)) { timeline in
ZStack {
Rectangle()
.foregroundStyle(LinearGradient(colors: [
Color.purple,
Color.blue
], startPoint: .top, endPoint: .bottom))
.ignoresSafeArea()
ForEach(circles) { circle in
Button(action: {
// Button action if needed
}) {
SwiftUI.Circle()
.foregroundStyle(Color.clear)
}
.glassEffect(.regular.tint(.white.opacity(0.5)).interactive())
.glassEffectID(circle.id, in: namespace)
.frame(width: circle.size, height: circle.size)
.position(circle.position)
.glassEffectID(circle.id, in: namespace)
}
}
.onChange(of: timeline.date) { oldValue, newValue in
if lastUpdate != nil {
updateCircles()
}
lastUpdate = newValue
}
}
.onAppear {
screenSize = geometry.size
initializeCircles()
}
}
}
}
private func initializeCircles() {
circles = (0..<20).map { _ in
let size = CGFloat.random(in: 40...120)
let x = CGFloat.random(in: size/2...(screenSize.width - size/2))
let y = CGFloat.random(in: size/2...(screenSize.height - size/2))
let vx = CGFloat.random(in: -0.5...0.5)
let vy = CGFloat.random(in: -0.5...0.5)
let hue = Double.random(in: 0...0.2) // Red to orange range
return Circle(
position: CGPoint(x: x, y: y),
velocity: CGVector(dx: vx, dy: vy),
size: size,
color: Color(hue: hue, saturation: 0.8, brightness: 0.9)
)
}
}
private func updateCircles() {
for i in circles.indices {
var circle = circles[i]
// Update position
circle.position.x += circle.velocity.dx
circle.position.y += circle.velocity.dy
// Check boundaries and bounce
let radius = circle.size / 2
if circle.position.x - radius <= 0 || circle.position.x + radius >= screenSize.width {
circle.velocity.dx *= -1
circle.position.x = max(radius, min(screenSize.width - radius, circle.position.x))
}
if circle.position.y - radius <= 0 || circle.position.y + radius >= screenSize.height {
circle.velocity.dy *= -1
circle.position.y = max(radius, min(screenSize.height - radius, circle.position.y))
}
circles[i] = circle
}
}
}
#Preview {
Lava()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment