Aeastr/Portal
Aeastr/Portal has 1,110 GitHub stars and 40 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-09 09:43 UTC. Last push 2026-09-26.
Portal is a SwiftUI package for element transitions across navigation contexts, scroll-based flowing headers, and advanced view mirroring capabilities.
Measured star growth
- in 24h
- 0
- in 7 days
- Update delayed
- in 15 days
- Update delayed
- in 1 month
- Update delayed
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
README.md
OriginalPortal 
Animate elements between screens, flow scrolling headers into navigation bars, and mirror views in SwiftUI.
Overview
Portal provides three modules for different use cases:
- PortalTransitions — Animate views between navigation contexts (sheets, navigation stacks, tabs) using a floating overlay layer. Uses standard SwiftUI APIs.
- PortalHeaders — Scroll-based header transitions that flow into the navigation bar, like Music or Photos. Uses iOS 18's advanced scroll tracking APIs.
- _PortalPrivate — True view mirroring using Apple's private
_UIPortalViewAPI. The view instance is shared rather than recreated.
Installation
dependencies: [
.package(url: "https://github.com/Aeastr/Portal.git", from: "4.0.0")
]
| Target | Description |
|---|---|
PortalTransitions |
Element transitions (iOS 17+) |
PortalHeaders |
Flowing headers (iOS 18+) |
_PortalPrivate |
View mirroring with private API |
Targeting iOS 15/16? Pin to
v2.1.0or thelegacy/ios15branch.
Usage
Element Transitions
// 1. Wrap your app in PortalContainer
PortalContainer {
ContentView()
}
// 2. Mark the source view
Image("cover")
.portal(id: "book", .source)
// 3. Mark the destination view
Image("cover")
.portal(id: "book", .destination)
// 4. Apply the transition
.fullScreenCover(item: $selectedBook) { book in
BookDetail(book: book)
}
.portalTransition(item: $selectedBook)
The view animates smoothly from source to destination when the cover presents, and back when it dismisses.
Flowing Headers
Scroll-based header transitions that flow into the navigation bar, like Music or Photos.
NavigationStack {
ScrollView {
PortalHeaderView()
ForEach(items) { item in
ItemRow(item: item)
}
}
.portalHeaderDestination()
}
.portalHeader(title: "Favorites", subtitle: "Your starred items")
Private API Mirroring
WARNING: Private API Usage
This module uses Apple's private
_UIPortalViewAPI. Apps using private APIs may be rejected by App Store Review. Use at your own discretion. Portal, Aether, and any maintainers assume no responsibility for App Store rejections, app crashes, or any other issues arising from the use of this module.
Same API as PortalTransitions, but uses Apple's private _UIPortalView for true view mirroring instead of layer snapshots. The view instance is shared rather than recreated.
Class names are obfuscated at compile-time. See Using _PortalPrivate for details.
Customization
Layer Configuration
Customize the animating layer with optional configuration closures:
// No config — frame/offset handled automatically
.portalTransition(item: $selectedBook) { book in
Image("cover")
}
// Styling only — add clips, shadows, etc. (frame/offset still automatic)
.portalTransition(item: $selectedBook) { book in
Image("cover")
} configuration: { content, isActive in
content.clipShape(.rect(cornerRadius: isActive ? 0 : 12))
}
// Full control — you handle frame/offset (for custom modifier ordering)
.portalTransition(item: $selectedBook) { book in
Image("cover")
} configuration: { content, isActive, size, position in
content
.frame(width: size.width, height: size.height)
.clipShape(.rect(cornerRadius: isActive ? 0 : 12))
.offset(x: position.x, y: position.y)
}
How It Works
PortalTransitions creates a transparent PassThroughWindow that sits above your entire app UI. Source and destination views register their bounds via PreferenceKey. When a transition triggers, the view is rendered in this overlay window and animated between the two positions. The window uses a custom hitTest implementation that only captures touches on the animated layer itself—all other touches pass through to your app below, so interaction remains seamless during animations.
PortalHeaders tracks scroll position using iOS 18's ScrollGeometry and interpolates between inline and navigation bar states based on content offset thresholds.
_PortalPrivate wraps Apple's private _UIPortalView class, which creates a portal to another view's layer. Class names are obfuscated at compile-time to avoid detection. See UIPortalBridge for a standalone wrapper.
Examples
Each module includes working examples in Sources/*/Examples/:
| PortalTransitions | PortalHeaders | _PortalPrivate |
|---|---|---|
| Card Grid | With Accessory | Card Grid |
| List | Title Only | List |
| Grid Carousel | No Accessory | Comparison |
Documentation
Guides and generated API documentation live in each module's DocC catalog:
Contributing
Contributions welcome. See the Contributing Guide for details.
License
MIT. See LICENSE for details.
Related
- UIPortalBridge - Standalone wrapper for
_UIPortalView - Transmission - UIKit-backed presentation and transitions for SwiftUI
Contact
Explore related projects
codecrafters-io/build-your-own-x
Master programming by recreating your favorite technologies from scratch.
561,398 starspublic-apis/public-apis
A collective list of free APIs
497,679 starsmorluto/rea
Reverse engineer anything with agents, from app behavior down to native binaries.
447,495 starsopenclaw/openclaw
The AI that really does things. Any OS. Any Platform. The lobster way. 🦞
394,261 stars