Aither is a dependency-free package for expressive, continuously looping particle orbs. Its primary API is native SwiftUI, backed by an efficient UIKit/Core Graphics renderer that can also be used directly.
- iOS 15 or later
- Swift 5.9 or later
- Xcode 15 or later
In Xcode, choose File → Add Package Dependencies and enter the repository URL:
https://github.com/hello-malek/Aither
Then add the Aither product to your application target.
For a vendored installation, copy Sources/Aither into your application target.
The package has no third-party dependencies.
import SwiftUI
import Aither
AitherOrb()
.aitherAnimation(.aither)
.aitherColors(.cyan, .purple)
.aitherSpeed(1.2)
.aitherIntensity(audioLevel)
.frame(width: 96, height: 96)aitherIntensity(_:) accepts a normalized live value such as an audio level or
network activity. When SwiftUI state changes, Aither updates the existing
renderer instead of recreating it.
| Aither | Zētēsis |
|---|---|
![]() |
![]() |
| Lysis | Akroasis |
![]() |
![]() |
| Synthesis | Morphōsis |
![]() |
![]() |
| Periphora | Diodos |
![]() |
![]() |
| Krystallos | Systolē |
![]() |
![]() |
Drive motion directly from SwiftUI state:
AitherOrb()
.aitherAnimation(.synthesis)
.aitherColors(.cyan, .indigo)
.aitherIntensity(audioLevel)
.aitherProgress(uploadProgress)
.aitherEmphasis(notificationStrength)
.aitherStatus(isComplete ? .success : .active)
.frame(width: 96, height: 96)All normalized inputs are clamped to 0...1 by the renderer. Changes are
interpolated by default, so noisy data does not produce visual jitter.
| Modifier | Purpose |
|---|---|
aitherAnimation(_:) |
Selects a continuously looping motion system. |
aitherColors(_:_:) |
Sets a depth-aware one- or two-color palette. |
aitherSpeed(_:) |
Sets the base playback-rate multiplier. |
aitherIntensity(_:) |
Drives motion with normalized live activity data. |
aitherProgress(_:) |
Supplies optional normalized progress. |
aitherEmphasis(_:) |
Supplies a normalized transient emphasis value. |
aitherStatus(_:) |
Sets idle, active, success, warning, or failure state. |
aitherParticleIntensity(_:) |
Controls particle contrast and opacity. |
aitherDensity(_:) |
Balances particle detail and rendering cost. |
aitherGlow(_:) |
Controls foreground particle halos. |
aitherDirection(_:) |
Selects forward or reverse playback. |
aitherPhaseOffset(_:) |
Desynchronizes multiple orb instances. |
aitherPhase(_:) |
Supplies an external phase; nil restores looping. |
aitherResponse(_:) |
Sets the live-data interpolation duration. |
aitherEasing(_:) |
Selects instant, smooth, spring, or cubic Bézier response. |
aitherQuality(_:) |
Selects automatic, low, or high rendering quality. |
aitherActivityMapping(_:) |
Maps activity to selected visual properties. |
aitherPaused(_:) |
Pauses or resumes playback from SwiftUI state. |
AitherView remains available for UIKit applications and advanced imperative
integration:
let orb = AitherView()
.animation(.energeia)
.palette(primary: .systemCyan, secondary: .systemPurple)
.speed(1.2)
orb.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(orb)
NSLayoutConstraint.activate([
orb.widthAnchor.constraint(equalToConstant: 96),
orb.heightAnchor.constraint(equalTo: orb.widthAnchor),
orb.centerXAnchor.constraint(equalTo: view.centerXAnchor),
orb.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])Apply one coherent UIKit input snapshot:
orb.update(
.init(
activity: audioLevel,
progress: processingProgress,
emphasis: 0.2
)
)Configure how UIKit input is interpolated:
orb
.response(0.3)
.mapActivity(to: [.speed, .deformation, .glow, .color])For exact timeline control, use setPhase(_:). Passing nil returns the orb to
its autonomous loop.
Combine publishers can drive complete inputs or individual values:
orb.bind(activity: activityPublisher)
orb.bind(progress: progressPublisher)
orb.bind(input: inputPublisher)Any sendable AsyncSequence of AitherView.OrbInput can also be consumed:
let task = orb.bind(input: inputStream)
// Cancel the task when the owning feature is released.
task.cancel()orb.setStatus(.active)
orb.setStatus(.success, animated: true)
orb.startAnimating()
orb.pauseAnimating()
orb.stopAnimating()Available statuses are idle, active, success, warning, and failure.
| API | Purpose |
|---|---|
animation(_:) |
Selects one of the ten looping motion systems. |
palette(primary:secondary:) |
Sets a depth-aware one- or two-color palette. |
speed(_:) |
Sets the base playback-rate multiplier. |
intensity(_:) |
Controls particle contrast and opacity. |
density(_:) |
Balances particle detail and rendering cost. |
glow(_:) |
Controls foreground particle halos. |
direction(_:) |
Selects forward or reverse playback. |
phaseOffset(_:) |
Desynchronizes multiple orb instances. |
response(_:) |
Sets data interpolation time. |
easing(_:) |
Selects instant, smooth, spring, or cubic Bézier response. |
quality(_:) |
Selects automatic, low, or high rendering quality. |
mapActivity(to:) |
Maps activity to selected visual properties. |
Aither automatically:
- respects Reduce Motion,
- lowers rendering cost in Low Power Mode,
- avoids drawing while outside the visible window area,
- pauses when its application enters the background,
- exposes status and progress through accessibility values.
The privacy manifest declares no tracking, collected data, tracking domains, or required-reason API usage.
Open Example/AitherPreview.xcodeproj and run the AitherPreview scheme to see
all included animation variants receiving live data.
Use GitHub Issues for reproducible bugs and feature requests. For direct contact, email:
Aither is available under the MIT License. See LICENSE.










