├── demo.gif
├── .gitignore
├── Package.swift
├── LICENSE
├── README.md
└── Sources
└── IntelligenceGlow
└── IntelligenceGlow.swift
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Livsy90/IntelligenceGlow/HEAD/demo.gif
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | xcuserdata/
5 | DerivedData/
6 | .swiftpm/configuration/registries.json
7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
8 | .netrc
9 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 6.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "IntelligenceGlow",
8 | platforms: [
9 | .iOS(.v15)
10 | ],
11 | products: [
12 | // Products define the executables and libraries a package produces, making them visible to other packages.
13 | .library(
14 | name: "IntelligenceGlow",
15 | targets: ["IntelligenceGlow"]
16 | ),
17 | ],
18 | targets: [
19 | // Targets are the basic building blocks of a package, defining a module or a test suite.
20 | // Targets can depend on other targets in this package and products from dependencies.
21 | .target(
22 | name: "IntelligenceGlow"
23 | ),
24 |
25 | ]
26 | )
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Artem
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 | # IntelligenceGlow
2 |
3 |
4 |
5 | A lightweight SwiftUI library that brings an **Apple Intelligence–style glowing stroke effect** to any `InsettableShape`.
6 | It uses animated angular gradients, layered blurs, and smooth transitions to recreate the dynamic glow seen in Apple’s design language.
7 |
8 | ## Features
9 |
10 | - ✨ Apply a glowing gradient as **background** or **overlay**
11 | - 🎨 Fully customizable line widths, blur radii, and animation durations
12 | - 🌈 Gradient stops automatically regenerate for a flowing effect
13 | - ♿ Respects **Reduce Motion** accessibility settings
14 | - 🧩 Works with any built-in `InsettableShape` (`Circle`, `Capsule`, `RoundedRectangle`, etc.)
15 |
16 | ## Installation
17 |
18 | ### Swift Package Manager
19 |
20 | In Xcode:
21 | `File > Add Packages > https://github.com/Livsy90/IntelligenceGlow.git`
22 |
23 | ## Usage
24 |
25 | ### Basic Example
26 |
27 | ```swift
28 | import SwiftUI
29 | import IntelligenceGlow
30 |
31 | struct ContentView: View {
32 | var body: some View {
33 | VStack(spacing: 30) {
34 | Text("Glowing Capsule")
35 | .padding(22)
36 | .intelligenceBackground(in: Capsule())
37 |
38 | Text("Glowing Rectangle")
39 | .padding(22)
40 | .intelligenceOverlay(in: RoundedRectangle(cornerRadius: 22))
41 | }
42 | }
43 | }
44 | ```
45 |
46 | ### Customizing the Glow
47 |
48 | You can control line widths, blurs, animation speed, and gradient generation:
49 |
50 | ```swift
51 | Text("Custom Glow")
52 | .padding(24)
53 | .intelligenceOverlay(
54 | in: Capsule(),
55 | lineWidths: [4, 8, 12],
56 | blurs: [0, 6, 12],
57 | updateInterval: 0.5,
58 | animationDurations: [0.6, 0.8, 1.2],
59 | gradientGenerator: { .intelligenceStyle }
60 | )
61 | ```
62 |
63 | ## API
64 |
65 | ### View Extensions
66 |
67 | ```swift
68 | func intelligenceBackground(in shape: S, ...)
69 | func intelligenceOverlay(in shape: S, ...)
70 | ```
71 |
72 | ### Shape Extension
73 |
74 | ```swift
75 | func intelligenceStroke(
76 | lineWidths: [CGFloat] = [6, 9, 11, 15],
77 | blurs: [CGFloat] = [0, 4, 12, 15],
78 | updateInterval: TimeInterval = 0.4,
79 | animationDurations: [TimeInterval] = [0.5, 0.6, 0.8, 1.0],
80 | gradientGenerator: @escaping () -> [Gradient.Stop] = { .intelligenceStyle }
81 | ) -> some View
82 | ```
83 |
84 | ## Preview
85 |
86 | ```swift
87 | #Preview {
88 | VStack(spacing: 30) {
89 | Text("Some text here")
90 | .padding(22)
91 | .intelligenceBackground(in: .capsule)
92 |
93 | Text("Some text here")
94 | .padding(22)
95 | .intelligenceOverlay(in: .rect(cornerRadius: 22))
96 | }
97 | }
98 | ```
99 |
--------------------------------------------------------------------------------
/Sources/IntelligenceGlow/IntelligenceGlow.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | public extension View {
4 | /// Applies a glowing angular-gradient stroke as a background using the provided shape.
5 | @MainActor
6 | func intelligenceBackground(
7 | in shape: S,
8 | lineWidths: [CGFloat] = [6, 9, 11, 15],
9 | blurs: [CGFloat] = [0, 4, 12, 15],
10 | updateInterval: TimeInterval = 0.4,
11 | animationDurations: [TimeInterval] = [0.5, 0.6, 0.8, 1.0],
12 | gradientGenerator: @MainActor @Sendable @escaping () -> [Gradient.Stop] = { .intelligenceStyle }
13 | ) -> some View {
14 | background(
15 | shape.intelligenceStroke(
16 | lineWidths: lineWidths,
17 | blurs: blurs,
18 | updateInterval: updateInterval,
19 | animationDurations: animationDurations,
20 | gradientGenerator: gradientGenerator
21 | )
22 | )
23 | }
24 |
25 | /// Applies a glowing angular-gradient stroke as an overlay using the provided shape.
26 | @MainActor
27 | func intelligenceOverlay(
28 | in shape: S,
29 | lineWidths: [CGFloat] = [6, 9, 11, 15],
30 | blurs: [CGFloat] = [0, 4, 12, 15],
31 | updateInterval: TimeInterval = 0.4,
32 | animationDurations: [TimeInterval] = [0.5, 0.6, 0.8, 1.0],
33 | gradientGenerator: @MainActor @Sendable @escaping () -> [Gradient.Stop] = { .intelligenceStyle }
34 | ) -> some View {
35 | overlay(
36 | shape.intelligenceStroke(
37 | lineWidths: lineWidths,
38 | blurs: blurs,
39 | updateInterval: updateInterval,
40 | animationDurations: animationDurations,
41 | gradientGenerator: gradientGenerator
42 | )
43 | )
44 | }
45 | }
46 |
47 | public extension InsettableShape {
48 | /// Applies an Apple Intelligence–style animated angular-gradient glow stroke to any Shape.
49 | /// - Parameters:
50 | /// - lineWidths: Line widths for each glow layer.
51 | /// - blurs: Blur radius for each corresponding glow layer.
52 | /// - updateInterval: How often to regenerate gradient stops.
53 | /// - animationDurations: Animation duration per layer when gradient changes.
54 | /// - gradientGenerator: Function that returns a new set of `Gradient.Stop` values.
55 | /// - Returns: A view that renders the shape with a glowing gradient stroke.
56 | @MainActor
57 | func intelligenceStroke(
58 | lineWidths: [CGFloat] = [6, 9, 11, 15],
59 | blurs: [CGFloat] = [0, 4, 12, 15],
60 | updateInterval: TimeInterval = 0.4,
61 | animationDurations: [TimeInterval] = [0.5, 0.6, 0.8, 1.0],
62 | gradientGenerator: @MainActor @Sendable @escaping () -> [Gradient.Stop] = { .intelligenceStyle }
63 | ) -> some View {
64 | IntelligenceStrokeView(
65 | shape: self,
66 | lineWidths: lineWidths,
67 | blurs: blurs,
68 | updateInterval: updateInterval,
69 | animationDurations: animationDurations,
70 | gradientGenerator: gradientGenerator
71 | )
72 | .allowsHitTesting(false)
73 | }
74 | }
75 |
76 | public extension Array where Element == Gradient.Stop {
77 | static var intelligenceStyle: [Gradient.Stop] {
78 | [
79 | Color(red: 188/255, green: 130/255, blue: 243/255),
80 | Color(red: 245/255, green: 185/255, blue: 234/255),
81 | Color(red: 141/255, green: 159/255, blue: 255/255),
82 | Color(red: 255/255, green: 103/255, blue: 120/255),
83 | Color(red: 255/255, green: 186/255, blue: 113/255),
84 | Color(red: 198/255, green: 134/255, blue: 255/255)
85 | ]
86 | .map {
87 | Gradient.Stop(color: $0, location: Double.random(in: 0...1))
88 | }
89 | .sorted {
90 | $0.location < $1.location
91 | }
92 | }
93 | }
94 |
95 | // MARK: - Generic glow stroke for any Shape
96 |
97 | private struct IntelligenceStrokeView: View {
98 | let shape: S
99 | let lineWidths: [CGFloat]
100 | let blurs: [CGFloat]
101 | let updateInterval: TimeInterval
102 | let animationDurations: [TimeInterval]
103 | let gradientGenerator: @MainActor @Sendable () -> [Gradient.Stop]
104 |
105 | @Environment(\.accessibilityReduceMotion) private var reduceMotion
106 | @State private var stops: [Gradient.Stop] = .intelligenceStyle
107 |
108 | var body: some View {
109 | let layerCount = min(lineWidths.count, blurs.count, animationDurations.count)
110 | let gradient = AngularGradient(
111 | gradient: Gradient(stops: stops),
112 | center: .center
113 | )
114 |
115 | ZStack {
116 | ForEach(0..