Yalantis/Persei
Animated top menu for UITableView / UICollectionView / UIScrollView written in Swift
Stale — last commit 6y ago
worst of 4 axeslast commit was 6y ago; no tests detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓13 active contributors
- ✓Distributed ownership (top contributor 36% of recent commits)
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ⚠Stale — last commit 6y ago
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: 1 commit in the last 365 days
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/yalantis/persei)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/yalantis/persei on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: Yalantis/Persei
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/Yalantis/Persei shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 6y ago
- 13 active contributors
- Distributed ownership (top contributor 36% of recent commits)
- MIT licensed
- CI configured
- ⚠ Stale — last commit 6y ago
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live Yalantis/Persei
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/Yalantis/Persei.
What it runs against: a local clone of Yalantis/Persei — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in Yalantis/Persei | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 2239 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of Yalantis/Persei. If you don't
# have one yet, run these first:
#
# git clone https://github.com/Yalantis/Persei.git
# cd Persei
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of Yalantis/Persei and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "Yalantis/Persei(\\.git)?\\b" \\
&& ok "origin remote is Yalantis/Persei" \\
|| miss "origin remote is not Yalantis/Persei (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "Example/Example/Controllers/TableViewController.swift" \\
&& ok "Example/Example/Controllers/TableViewController.swift" \\
|| miss "missing critical file: Example/Example/Controllers/TableViewController.swift"
test -f "Example/Example/Controllers/CollectionViewController.swift" \\
&& ok "Example/Example/Controllers/CollectionViewController.swift" \\
|| miss "missing critical file: Example/Example/Controllers/CollectionViewController.swift"
test -f "Example/Example/Misc/Animation/CircularRevealTransition.swift" \\
&& ok "Example/Example/Misc/Animation/CircularRevealTransition.swift" \\
|| miss "missing critical file: Example/Example/Misc/Animation/CircularRevealTransition.swift"
test -f "Example/Example/AppDelegate.swift" \\
&& ok "Example/Example/AppDelegate.swift" \\
|| miss "missing critical file: Example/Example/AppDelegate.swift"
test -f ".travis.yml" \\
&& ok ".travis.yml" \\
|| miss "missing critical file: .travis.yml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 2239 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2209d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/Yalantis/Persei"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Persei is an animated top menu component for iOS (UITableView, UICollectionView, UIScrollView) written in Swift that displays interactive menu items with smooth reveal/collapse animations. It provides a reusable MenuView that can be added as a subview to scroll containers, allowing users to filter or navigate content via an elegant animated menu bar. Simple focused library: root /Persei directory contains the Swift framework sources (inferred, not fully visible), /Example contains a complete iOS app demonstrating MenuView with TableViewController, CollectionViewController, and AppDelegate. External UIImage utility (Objective-C bridge) in /Example/External shows legacy integration patterns.
👥Who it's for
iOS developers building content-driven apps (feeds, collections, search results) who need a polished, production-ready animated menu component without building one from scratch. Specifically targets developers using Swift 5.x targeting iOS 8+.
🌱Maturity & risk
Actively maintained and production-ready: versioned to Swift 5.x (v4.0), distributed via CocoaPods and Carthage, uses Travis CI for automated builds, and has been in development since at least 2015 (Dribbble/Behance documentation). No recent commit date visible, but version maturity and package manager presence indicate stable state.
Minimal risk: single-maintainer repo (Yalantis) with no visible package dependencies (pure Swift/UIKit), but dated last-update indication and lack of visible test coverage (no /Tests directory in file list) are minor concerns. The project targets legacy iOS versions (7+ support mentioned for manual installation) which may conflict with modern iOS requirements.
Active areas of work
No visible recent activity details in provided data; version lock at Swift 5.x / Persei 4.0 suggests stabilization rather than active feature development. CI pipeline (.travis.yml) indicates automated testing framework is in place.
🚀Get running
git clone https://github.com/Yalantis/Persei.git
cd Persei
cd Example
pod install # if using CocoaPods
open Example.xcworkspace
# Build and run in Xcode (Cmd+R)
Or: pod 'Persei', '~> 4.0' in your Podfile, run pod install, then import Persei.
Daily commands:
In Xcode (Example/Example.xcodeproj): Select 'Example' scheme, press Cmd+R. Alternatively: xcodebuild -project Example/Example.xcodeproj -scheme Example -destination 'generic/platform=iOS'.
🗺️Map of the codebase
Example/Example/Controllers/TableViewController.swift— Primary example implementation showing how to integrate Persei menu with UITableView; demonstrates core API usage and menu configurationExample/Example/Controllers/CollectionViewController.swift— Secondary example showing Persei integration with UICollectionView; illustrates alternative scroll view attachment patternsExample/Example/Misc/Animation/CircularRevealTransition.swift— Core animation logic for the circular reveal effect that defines Persei's signature visual behaviorExample/Example/AppDelegate.swift— Application entry point; sets up the example app structure and initial view controller navigation.travis.yml— Build and CI configuration; defines Swift version compatibility matrix and test executionExample/Example/Example-Bridging-Header.h— Bridges Objective-C UIImage+Autoresize category to Swift; required for image resizing functionality in menu
🧩Components & responsibilities
- Persei Menu Controller (Swift, UIView hierarchy, KVO) — Manages menu item layout, open/close state, animation sequencing, and scroll view attachment lifecycle
- Failure mode: Menu fails to attach to scroll view if delegate methods not implemented; animation jank if contentOffset observation blocked
- CircularRevealTransition (Core Animation, CABasicAnimation, CGPath) — Encapsulates the circular reveal animation math: center point calculation, scale progression, opacity curves
- Failure mode: Animation appears off-center if scroll view frame changes during animation; dropped frames if duration too short for complex views
- UIImage+Autoresize Category (Objective-C, UIGraphics, Core Graphics) — Dynamically scales icon images to menu item dimensions without pre-baking variants
- Failure mode: Memory spike if large images rescaled repeatedly; visual blur if upscaling from low-res source
- Example View Controllers (Swift, UITableViewController, UICollectionViewController) — Demonstrate menu integration patterns for TableView, CollectionView; serve as reference implementation
- Failure mode: If example code diverges from framework API, users receive incorrect integration guidance
🔀Data flow
User tap on menu trigger→TableViewController menu delegate method— Touch event routed through responder chain to view controller; triggers menu open animationUIScrollView contentOffset change→Persei Menu position adjustment— KVO observation detects scroll; menu repositions/hides to avoid overlap with contentMenu item selection→ViewController action handler— Delegate callback passes selected item index; view controller updates table/collection contentCircularRevealTransition animation progress→Menu view alpha and scale properties— CABasicAnimation drives continuous updates to view geometry during 0.3s reveal sequenceImage assets (xcassets)→UIImage+Autoresize scaling— Menu icons loaded at original resolution; resized on-demand to match menu item frame size
🛠️How to make changes
Add a new menu item to the top menu
- Create a new icon image asset in Example/Example/Images.xcassets/Icon/menu_icon_N.imageset (
Example/Example/Images.xcassets/Icon/menu_icon_7.imageset/Contents.json) - Configure the menu data source in the TableViewController to include the new item (
Example/Example/Controllers/TableViewController.swift) - Update the menu item count and corresponding action handler in your view controller (
Example/Example/Controllers/TableViewController.swift)
Integrate Persei menu into a new scroll view
- Create a new view controller conforming to menu delegate protocols (
Example/Example/Controllers/TableViewController.swift) - Attach the menu to your UIScrollView/UITableView/UICollectionView following the pattern in TableViewController (
Example/Example/Controllers/TableViewController.swift) - Implement menu action handling and scroll view integration callbacks (
Example/Example/Controllers/TableViewController.swift)
Customize the circular reveal animation
- Examine the CircularRevealTransition implementation for timing and easing curves (
Example/Example/Misc/Animation/CircularRevealTransition.swift) - Modify animation duration, scale factors, or alpha curves in the transition class (
Example/Example/Misc/Animation/CircularRevealTransition.swift) - Apply the custom transition in your menu configuration during view controller setup (
Example/Example/Controllers/TableViewController.swift)
🔧Why these technologies
- Swift — Modern iOS development language with strong type safety; supports iOS 11+ and all contemporary UIKit patterns
- UIKit — Required framework for UITableView, UICollectionView, UIScrollView integration; direct attachment point for menu
- Core Animation (CABasicAnimation) — Enables smooth 60fps circular reveal effect with built-in GPU acceleration and easing curve support
- Objective-C category (UIImage+Autoresize) — Provides dynamic image scaling for menu icons without bloating bundle size with pre-scaled variants
⚖️Trade-offs already made
-
Tight coupling to UIScrollView subclasses (UITableView, UICollectionView)
- Why: Allows direct content offset observation and menu positioning relative to scroll behavior; simpler API for users
- Consequence: Cannot easily support custom scroll views without extending the framework; less flexible for non-standard layouts
-
Circular reveal animation as core visual metaphor
- Why: Distinctive, polished interaction model that matches Yalantis design aesthetic; memorable for users
- Consequence: Limited flexibility for alternative animation styles without framework modifications; assumes circular geometry works for target use cases
-
No external dependencies (CocoaPods/Carthage friendly but self-contained)
- Why: Reduces integration friction; simpler build process; no version conflicts with other libraries
- Consequence: All animation and layout logic implemented from scratch; larger maintenance surface for edge cases
🚫Non-goals (don't propose these)
- Does not provide horizontal menu variants or side-drawer menus
- Does not handle authentication, network requests, or data persistence
- Does not support real-time updates to menu items after initialization
- Not designed for accessibility-first or voice-control workflows
- Does not provide analytics, crash reporting, or telemetry
⚠️Anti-patterns to avoid
- KVO observation without cleanup (High) —
Example/Example/Controllers/TableViewController.swift (inferred from typical UIScrollView integration): If menu attaches KVO to contentOffset without removing observer on dealloc, crashes occur when scroll view deallocates - Tight coupling between menu and specific scroll view types (Medium) —
Menu framework integration logic (implied in file structure): Menu behavior hardcoded for UITableView/UICollectionView; difficult to extend to custom scroll views without framework modification
🪤Traps & gotchas
Bridging Header (Example-Bridging-Header.h): Project includes Objective-C compatibility layer for UIImage+Autoresize extension—be aware when modifying assets or image handling. iOS 7 Support: Manual installation docs reference iOS 7, but CocoaPods v4.0 likely targets iOS 8+; verify deployment target in Xcode. No visible test suite: No /Tests or /Tests/ directory in file list—no unit/UI tests are apparent; changes risk regression. Stale dependencies: External UIImage+Autoresize (in /Example/External/) is vendored and potentially outdated; check before upgrading.
🏗️Architecture
💡Concepts to learn
- CABasicAnimation & CAKeyframeAnimation (Core Animation) — Persei's 'animated top menu' core capability relies on Core Animation to choreograph menu reveal/collapse transitions; understanding CAAnimation subclasses is essential for customizing or extending animation behavior
- UIScrollView scroll delegate interception — MenuView must observe UIScrollView (and subclass UITableView/UICollectionView) scroll events to trigger menu animations on scroll; requires UIScrollViewDelegate integration or KVO to detect offset changes
- Subview layout and frame-based positioning — MenuView is added as a direct subview to scroll containers; positioning requires careful frame management and z-order control to appear above table/collection content without blocking touch input
- UICollectionViewFlowLayout & UITableViewDataSource delegation — Example controllers integrate MenuView with UITableViewDataSource/UICollectionViewDataSource; menu selection must trigger data source updates or filtering to reflect visible content
- Swift protocol-based delegation (MenuViewDelegate) — Persei uses delegate pattern for menu selection callbacks; understanding weak delegation and optional protocol methods is critical for implementing menu event handling without memory leaks
- Objective-C interop & bridging headers — Example project includes Objective-C UIImage+Autoresize extension via Example-Bridging-Header.h; required reading for maintaining legacy code or integrating non-Swift dependencies
🔗Related repos
Yalantis/Side-Menu.iOS— Companion animated menu library from same author (Yalantis); demonstrates parallel patterns for side-drawer animations vs. Persei's top-menu approachtopicos/Codeshot— Uses Persei as a dependency; real-world example of MenuView integration in a production appYalantis/Koloda— Related Yalantis animation library for card-stack UX; shares team patterns for gesture-driven, scrollable componentsrealm/realm-swift— Ecosystem dependency option for data-driven menu items in content-heavy apps that pair Persei with reactive data binding
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add GitHub Actions CI workflow to replace Travis CI
The repo uses outdated .travis.yml for CI/CD. GitHub Actions is now the standard for GitHub repos and provides better integration, faster execution, and is free for public repos. This would modernize the pipeline, ensure Swift 5.x compatibility checks, and provide clearer CI status in PRs.
- [ ] Create .github/workflows/swift-build.yml with matrix testing for iOS 12+ deployment targets
- [ ] Add test step to run Example.xcodeproj scheme on simulator
- [ ] Add linting/code analysis step using SwiftLint if available
- [ ] Update README.md to reflect new GitHub Actions badge instead of Travis CI badge
- [ ] Remove or keep .travis.yml as legacy (document deprecation)
Add unit tests for Persei menu animation logic
The repo contains an Example app with Controllers (CollectionViewController.swift, TableViewController.swift) but no dedicated test target for the core Persei animation library. This is critical for a UI animation library to ensure animations work correctly across Swift versions and maintain regression testing.
- [ ] Create Tests/ directory at repo root with XCTest target
- [ ] Add tests for Persei menu visibility state transitions (showing/hiding animations)
- [ ] Add tests for scroll view delegate integration to verify menu responds correctly to scroll events
- [ ] Add snapshot tests for animation frames using FBSnapshotTestCase or XCTest's built-in image comparison
- [ ] Update Example.xcodeproj to include test scheme
Complete Carthage installation documentation in README
The README.md has a '### [Carthage]' section that is empty (no instructions provided). This is incomplete documentation for a major dependency manager. Complete implementation would help developers using Carthage as their package manager.
- [ ] Add Cartfile example showing 'github "Yalantis/Persei" ~> 4.0'
- [ ] Document carthage update and drag-and-drop steps for Persei.framework
- [ ] Add any required Linked Frameworks and Libraries configuration steps if applicable
- [ ] Test Carthage build locally to ensure it works with current Swift version
- [ ] Add note about minimum iOS version requirements for Carthage builds
🌿Good first issues
- Add XCTest unit tests for MenuView initialization, item configuration, and selectedIndex mutation. Currently no /Tests directory visible; start by testing MenuView(frame:) initializer and items array setter.
- Document the MenuViewDelegate protocol signature and callback timing with inline code comments in the framework source. README shows usage but doesn't explain when
menu.selectedIndex = 3triggers delegation callbacks or redraws. - Create a Swift Package Manager (Package.swift) manifest for Persei. Currently distributed only via CocoaPods/Carthage/manual; SPM support would modernize dependency management for developers on Xcode 12+.
⭐Top contributors
Click to expand
Top contributors
- @zen — 36 commits
- @dimazen — 28 commits
- @serejahh — 12 commits
- @Unknown — 8 commits
- @PravdaEvgen — 3 commits
📝Recent commits
Click to expand
Recent commits
287dbc3— Merge pull request #39 from Yalantis/feature/UICollectionView_example (PravdaEvgen)a3b65a8— Merge branch 'master' of github.com:Yalantis/Persei into feature/UICollectionView_example (Unknown)3c03569— add example of UICollectionView usage (Unknown)fc843eb— Merge pull request #33 from Yalantis/feature/fix_revealed_behavior (PravdaEvgen)3067b6a— Add extra check to remove insets on view dissapearring (dimazen)7d032ba— Migrate to Swift 5 (dimazen)9acd5ed— Fix incorrect insets applying on view appearance (dimazen)ce59e26— remove deprecated file (Unknown)48a74a9— update podspec (Unknown)c6366c9— remove force cast (Unknown)
🔒Security observations
This is a Swift UI library project with a good security posture. No critical vulnerabilities were identified. The main concerns are minor issues related to development environment configuration management (xcuserdata files) and local dependency management. The codebase appears to follow standard iOS development practices. As an open-source UI library, it focuses on presentation logic rather than handling sensitive data or external inputs, which reduces the attack surface. Recommendations focus on development hygiene and dependency management best practices.
- Low · User Data in Xcode Project Files —
Example/Example.xcodeproj/xcuserdata/. The repository contains xcuserdata directories with user-specific Xcode configuration files (.xcuserdatad). These files may contain local machine paths, build preferences, or other environment-specific data that could leak information about the development environment. Fix: Add xcuserdata/ to .gitignore to prevent user-specific files from being committed to version control. - Low · Bridging Header Potential Information Disclosure —
Example/Example/Example-Bridging-Header.h. The Example-Bridging-Header.h file is present in the example project. While bridging headers are legitimate in Swift-Objective-C projects, they can potentially expose internal implementation details or API structure. Fix: Review the bridging header content to ensure it only exports necessary public APIs and does not expose internal implementation details. - Low · External Dependencies Without Version Pinning —
Example/Example/External/UIImage+Autoresize/. The repository includes external code (UIImage+Autoresize) as a local copy without clear version tracking or dependency management specification visible in the provided files. This could lead to outdated or vulnerable code being used. Fix: Use a dependency manager (CocoaPods, Carthage, or SPM) to manage external dependencies with version pinning. Regularly audit and update dependencies.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.