
Mesh Gradient
From syxUI — written for both platforms, not translated between them.
A soft nine-point colour field, gently warping. Native MeshGradient on iOS 18.
Backgrounds · SwiftUI · Flutter · iOS 17 · Flutter 3.27
- background
- mesh
- gradient
- colour
- ambient
- soft
The actual source
MeshBackground.swift
// Mesh Gradient · syxUI · https://syxui.dev/components/mesh-gradient
// Free in any project. Keep this line and credit syxUI where a person can read it.
import SwiftUI
/// A soft mesh gradient field.
///
/// Uses SwiftUI's native `MeshGradient` on iOS 18 and falls back to layered
/// radial gradients before that, so it renders on every supported OS without
/// a branch at the call site.
struct MeshBackground: View {
var colors: [Color] = [
Color(red: 0.99, green: 0.85, blue: 0.72), Color(red: 0.98, green: 0.72, blue: 0.80), Color(red: 0.85, green: 0.74, blue: 0.99),
Color(red: 0.99, green: 0.78, blue: 0.66), Color(red: 0.93, green: 0.80, blue: 0.98), Color(red: 0.72, green: 0.82, blue: 0.99),
Color(red: 0.98, green: 0.88, blue: 0.78), Color(red: 0.78, green: 0.88, blue: 0.99), Color(red: 0.70, green: 0.90, blue: 0.94),
]
var animated: Bool = true
var period: Double = 9
/// Drive the warp yourself with 0...1 instead of letting it animate.
var phase: Double? = nil
@Environment(\.accessibilityReduceMotion) private var reduceMotion
@State private var animatedWarp: Float = 0
/// Mapped through a cosine so t = 0 and t = 1 are the same frame.
private var warp: Float {
if let phase { return Float((1 - cos(phase * 2 * .pi)) / 2) }
return animatedWarp
}
var body: some View {
Group {
if #available(iOS 18.0, macOS 15.0, *) {
MeshGradient(width: 3, height: 3, points: points, colors: colors)
} else {
fallback
}
}
.onAppear {
guard animated, !reduceMotion, phase == nil else { return }
withAnimation(.easeInOut(duration: period).repeatForever(autoreverses: true)) {
animatedWarp = 1
}
}
.accessibilityHidden(true)
}
/// A 3×3 control lattice. Only the middle row and column move, which keeps
/// the corners pinned and stops the field from sliding off its own edges.
private var points: [SIMD2<Float>] {
let mid = 0.5 + warp * 0.26
let low = 0.5 - warp * 0.22
return [
.init(0, 0), .init(Float(low), 0), .init(1, 0),
.init(0, 0.5), .init(Float(mid), Float(mid)), .init(1, Float(low)),
.init(0, 1), .init(Float(mid), 1), .init(1, 1),
]
}
private var fallback: some View {
ZStack {
colors.first ?? .clear
ForEach(Array(colors.enumerated()), id: \.offset) { index, color in
let column = Double(index % 3) / 2
let row = Double(index / 3) / 2
RadialGradient(
colors: [color.opacity(0.9), color.opacity(0)],
center: UnitPoint(x: column, y: row),
startRadius: 0,
endRadius: 220
)
}
}
.blur(radius: 28)
.clipped()
}
}
#Preview {
MeshBackground()
.frame(width: 400, height: 300)
}
iOS 17 · No dependencies
SwiftUI note. MeshGradient is iOS 18+. The included fallback keeps iOS 17 working, so the call site never needs an availability check.
Dependencies
- SwiftUI
- No external dependencies
- Flutter
- No external dependencies
Requires iOS 17
Requires Flutter 3.27


