shoheiyokoyama/Gemini
Gemini is rich scroll based animation framework for iOS, written in Swift.
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
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.
- ✓Last commit 11mo ago
- ✓5 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Slowing — last commit 11mo ago
- ⚠Single-maintainer risk — top contributor 95% of recent commits
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 "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/shoheiyokoyama/gemini)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/shoheiyokoyama/gemini on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: shoheiyokoyama/Gemini
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/shoheiyokoyama/Gemini 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
GO — Healthy across all four use cases
- Last commit 11mo ago
- 5 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Slowing — last commit 11mo ago
- ⚠ Single-maintainer risk — top contributor 95% of recent commits
<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 shoheiyokoyama/Gemini
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/shoheiyokoyama/Gemini.
What it runs against: a local clone of shoheiyokoyama/Gemini — 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 shoheiyokoyama/Gemini | 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 ≤ 346 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of shoheiyokoyama/Gemini. If you don't
# have one yet, run these first:
#
# git clone https://github.com/shoheiyokoyama/Gemini.git
# cd Gemini
#
# 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 shoheiyokoyama/Gemini and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "shoheiyokoyama/Gemini(\\.git)?\\b" \\
&& ok "origin remote is shoheiyokoyama/Gemini" \\
|| miss "origin remote is not shoheiyokoyama/Gemini (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 "Gemini/GeminiCollectionView.swift" \\
&& ok "Gemini/GeminiCollectionView.swift" \\
|| miss "missing critical file: Gemini/GeminiCollectionView.swift"
test -f "Gemini/GeminiCell.swift" \\
&& ok "Gemini/GeminiCell.swift" \\
|| miss "missing critical file: Gemini/GeminiCell.swift"
test -f "Gemini/GeminiAnimationModel.swift" \\
&& ok "Gemini/GeminiAnimationModel.swift" \\
|| miss "missing critical file: Gemini/GeminiAnimationModel.swift"
test -f "Gemini/CircleRotateAnimatable.swift" \\
&& ok "Gemini/CircleRotateAnimatable.swift" \\
|| miss "missing critical file: Gemini/CircleRotateAnimatable.swift"
test -f "Gemini/EasingFunction.swift" \\
&& ok "Gemini/EasingFunction.swift" \\
|| miss "missing critical file: Gemini/EasingFunction.swift"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 346 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~316d)"
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/shoheiyokoyama/Gemini"
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
Gemini is a UICollectionView-based animation framework for iOS that binds scroll events to rich, chainable animations (3D rotations, scaling, custom transforms). It solves the problem of adding sophisticated parallax and motion effects to collection views without manual scroll delegate boilerplate, providing pre-built animations like CircleRotation, CubeRotation, and PitchRotation alongside a fluent API for custom animations. Single-framework project structure: Sources/ contains the core Gemini library (likely GeminiCollectionView and animation builders), Example/Gemini/ is a runnable demo app with 8 ViewControllers (AnimationListViewController, CircleRotationViewController, CubeViewController, etc.), each showcasing one animation type with a paired Storyboard.
👥Who it's for
iOS developers building apps with scrolling image galleries or feeds (e.g., in Example/ see image-heavy UIs) who want production-grade scroll-linked animations without writing CADisplayLink or scroll event handlers manually.
🌱Maturity & risk
Actively maintained and production-ready. Tagged at v1.4.0 with Swift 5.0 support, CocoaPods/Carthage integration, Travis CI configured (.travis.yml present), and a comprehensive example app demonstrating 7+ animation types. No visible abandoned signals, but appears to be a focused library rather than a high-traffic project.
Low risk for a focused library: single maintainer (shoheiyokoyama) is a known risk, but the codebase is 90% Swift with minimal external dependencies (none visible in snippet). Last activity not shown in data, so verify commit recency on GitHub. No test suite mentioned in file structure—animation behavior not formally verified.
Active areas of work
No active development signals visible in the file list (no open PRs/issues provided). The Example app is feature-complete with all major animation types implemented. Likely in maintenance mode: accepting fixes rather than new features.
🚀Get running
Clone and open in Xcode: git clone https://github.com/shoheiyokoyama/Gemini.git && cd Gemini/Example && open Gemini.xcworkspace. CocoaPods: add pod 'Gemini' to Podfile. See CHANGELOG.md and Example/ ViewControllers for usage examples.
Daily commands:
open Example/Gemini.xcworkspace in Xcode (note: .xcworkspace not .xcodeproj to handle CocoaPods). Select a simulator/device target and press Run, or tap through AnimationListViewController to view each animation type.
🗺️Map of the codebase
Gemini/GeminiCollectionView.swift— Core subclass of UICollectionView that enables scroll-based animations; entry point for all animation configurationsGemini/GeminiCell.swift— Base cell class that integrates with GeminiCollectionView to apply animations during scroll; essential for animation applicationGemini/GeminiAnimationModel.swift— Data model defining animation properties and configurations; foundational abstraction for all animation typesGemini/CircleRotateAnimatable.swift— Protocol and implementation for circle rotation animations; exemplifies the animatable protocol pattern used throughoutGemini/EasingFunction.swift— Timing functions for animation interpolation; critical for smooth animation transitionsGemini/UIViewExtension.swift— Extensions adding gemini animation configuration to UIView; enables fluent method-chaining API
🧩Components & responsibilities
- GeminiCollectionView (UICollectionView, UIScrollViewDelegate) — Intercepts scroll events, calculates normalized offset, queries animation models, and triggers cell updates
- Failure mode: Scroll events not delivered → animations freeze at current state
- GeminiCell (UICollectionViewCell, CALayer) — Receives transform commands from collection view and applies them to content view layer
- Failure mode: Transform application fails → cell appears unannimated despite scroll
- GeminiAnimationModel (Swift structs, generics) — Stores animation type, parameters, and provides evaluation function mapping offset→CATransform3D
- Failure mode: Invalid model state → transform calculations produce incorrect or NaN values
- Animatable Protocols (CircleRotate, Cube, Scale, etc) (Swift protocols, CATransform3D, matrix math) — Define animation-specific transform logic; each implements calculation of CATransform3D from normalized progress
- Failure mode: Protocol implementation error → animations appear jerky, distorted, or use wrong axes
- EasingFunction (Timing function math, Bezier curves) — Maps linear scroll progress (0.0→1.0) to nonlinear timing curves (ease-in, ease-out, cubic, etc)
- Failure mode: Incorrect
🛠️How to make changes
Add a new scroll-based animation type
- Create new file named YourAnimationAnimatable.swift in Gemini/ directory (
Gemini/YourAnimationAnimatable.swift) - Implement protocol conforming to animation interface (reference CircleRotateAnimatable.swift for pattern) (
Gemini/YourAnimationAnimatable.swift) - Add configuration method to UIViewExtension.swift with fluent chainable interface (
Gemini/UIViewExtension.swift) - Create new ViewController in Example/Gemini/ViewControllers/ to demonstrate the animation (
Example/Gemini/ViewControllers/YourAnimationViewController.swift) - Register new animation in AnimationListViewController.swift with navigation entry (
Example/Gemini/ViewControllers/AnimationListViewController.swift)
Create a custom scroll animation
- Reference CustomAnimatable.swift protocol to understand required implementation (
Gemini/CustomAnimatable.swift) - In your ViewController, access collectionView.gemini.customAnimation() and define transform closure (
Example/Gemini/ViewControllers/CustomAnimationViewController.swift) - Use the scroll offset parameter to calculate custom CATransform3D transformations (
Gemini/GeminiAnimationModel.swift) - Apply easing functions from EasingFunction.swift for smooth interpolation if needed (
Gemini/EasingFunction.swift)
Configure animation on collection view
- Ensure collection view is instance of GeminiCollectionView (or subclass it) (
Gemini/GeminiCollectionView.swift) - Access collectionView.gemini property to start fluent configuration chain (
Gemini/UIViewExtension.swift) - Chain animation method (e.g. .circleRotationAnimation()) with property setters for customization (
Example/Gemini/ViewControllers/CircleRotationViewController.swift) - Ensure collection view cells inherit from GeminiCell for animation application (
Gemini/GeminiCell.swift)
🔧Why these technologies
- Swift — Modern iOS development language with strong type safety and protocol-oriented design supporting fluent APIs
- CATransform3D — Core Animation transforms provide GPU-accelerated 3D perspective and rotation without frame-by-frame redrawing
- UICollectionView — Recycled cell architecture handles large scrollable content efficiently; subclassing enables animation interception at scroll points
- Protocol-Oriented Design — Animatable protocols allow pluggable animation implementations enabling composition and custom extension without inheritance chains
⚖️Trade-offs already made
-
Scroll-based animation vs time-based animation
- Why: Scroll events directly drive animation progress tied to UIScrollView offset rather than elapsed time
- Consequence: Animations are perfectly synchronized to scroll velocity but cannot run independently of user interaction
-
Fluent method chaining API vs builder pattern
- Why: Configuration uses chainable methods returning self for intuitive inline configuration
- Consequence: Reduces boilerplate but tightly couples UIView/UICollectionView extensions to GeminiAnimationModel
-
Subclass GeminiCell vs category/extension approach
- Why: GeminiCell subclass provides dedicated animation lifecycle hooks
- Consequence: Requires all animated cells to inherit from GeminiCell reducing flexibility with existing cell hierarchies
🚫Non-goals (don't propose these)
- Does not support time-based animations independent of scroll
- Does not provide gesture-based animation triggers (swipe, tap, pinch)
- Does not support animations on non-collection-view scrollable containers (UITableView, UIScrollView without collection view wrapper)
- Does not include built-in physics or spring animation engines
🪤Traps & gotchas
- Open Example/Gemini.xcworkspace, not Example/Gemini.xcodeproj—CocoaPods pods won't resolve otherwise. 2. GeminiCollectionView requires explicit scroll direction (vertical/horizontal) configuration via the fluent API; misconfiguration causes animations to not trigger. 3. Animation values like radius(400) are hardcoded in examples—test on different screen sizes as values may be device-dependent. 4. No visible unit tests: animation behavior is only validated visually in the example app.
🏗️Architecture
💡Concepts to learn
- CATransform3D and 3D affine transforms — Gemini's core mechanism—all rotation animations (CircleRotation, Pitch, Roll, Yaw, Cube) rely on CATransform3D matrix multiplication to rotate cells in 3D space; understanding perspective and z-axis transforms is essential
- Method chaining / Fluent interface pattern — Gemini's entire API is built on method chaining (e.g., .circleRotationAnimation().radius(400).rotateDirection(.clockwise)); understanding this pattern is required to use or extend the library
- UICollectionViewDelegate scroll event interception — GeminiCollectionView subclasses UICollectionView and overrides scrollViewDidScroll() to trigger animations; understanding scroll delegate callbacks is critical for modifying or debugging animation timing
- Easing functions / Animation curves — Gemini supports easing (mentioned in README and features list) to smooth animation acceleration—cubic ease-in/out, linear, etc. make animations feel natural rather than mechanical
- CABasicAnimation and CAAnimationGroup — Likely used internally by Gemini to animate cell transforms across scroll ranges; understanding these Core Animation primitives helps debug frame rate and performance issues
- Scroll-linked animation and parallax — The core problem Gemini solves—binding animation progress directly to scroll position (not time) so effects synchronize with user gestures; this requires manual scroll offset tracking
- Builder pattern for animation configuration — Each animation type (CircleRotation, Cube, etc.) is built via a builder that accumulates properties (.radius(400), .rotateDirection(...)) before binding to the collection view; understanding this pattern helps extend animations
🔗Related repos
airbnb/lottie-ios— Both enable rich animations on iOS; Lottie is for keyframe animations from After Effects, Gemini is specifically for scroll-linked collection view effectsfacebook/pop— Pop is a general-purpose animation framework (spring dynamics, etc.); Gemini layers scroll-binding on top for collection viewsCocoaPods/CocoaPods— Gemini is distributed via CocoaPods—understanding pod spec and dependency management is required for installationrealm/realm-swift— Often paired with Gemini in image/gallery apps; provides efficient local data storage for collection view datasourceskingfisher-io/Kingfisher— Commonly used alongside Gemini for image caching in animated collection views (the example app's building.jpg, food.jpg images would benefit from this)
🪄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 unit tests for GeminiCollectionView animation calculations
The repo has multiple animation types (circleRotation, pitch, roll, yaw, cube, scale) but no visible test suite. Testing the core animation calculation logic would ensure reliability across iOS versions and prevent regressions when animations are modified. This is critical for a framework where animation accuracy is the primary value proposition.
- [ ] Create Tests/ directory with GeminiCollectionViewTests.swift
- [ ] Add unit tests for each animation type's attribute calculations (radius, rotateDirection, etc.)
- [ ] Test the fluent interface method chaining to ensure configuration objects are built correctly
- [ ] Add tests for edge cases like extreme scroll offsets and collection view boundary conditions
Add GitHub Actions CI/CD workflow with iOS testing and Cocoapods validation
The repo has .travis.yml indicating legacy Travis CI, but modern iOS projects use GitHub Actions. Adding a workflow to run tests on each PR and validate the .podspec file would catch integration issues early. This is especially important since the repo is distributed via Cocoapods (referenced in Podfile/Pods directory).
- [ ] Create .github/workflows/ios-tests.yml to run unit tests on multiple iOS versions
- [ ] Add pod spec validation step to verify Example/Pods/Local Podspecs/Gemini.podspec.json is valid
- [ ] Include code linting/formatting checks for Swift code in Sources/ directory
- [ ] Update .travis.yml or remove if GitHub Actions becomes the standard
Extract and document the custom animation API with usage examples in docs/
The repo shows CustomAnimationViewController.swift in the example app, indicating custom animations are possible, but there's no dedicated documentation explaining how to create custom scroll animations. This is a key differentiator ('create your own custom scroll animation') that new contributors can't leverage. Adding clear docs with code examples would lower the barrier to contribution.
- [ ] Create docs/CUSTOM_ANIMATIONS.md with step-by-step guide and code examples
- [ ] Reference the GeminiCollectionViewDelegate/DataSource protocols and animation protocols
- [ ] Include example code from Example/Gemini/ViewControllers/CustomAnimationViewController.swift
- [ ] Add troubleshooting section for common animation issues (timing, performance)
🌿Good first issues
- Add unit tests for each animation type (CircleRotation, Cube, Pitch/Roll/Yaw, Scale) in Sources/ to verify transform calculations—currently only the example app validates behavior
- Create a SwiftUI wrapper (GeminiCollectionViewRepresentable) to bridge Gemini into modern SwiftUI apps, given the shift from UIKit in iOS 13+
- Document easing function usage in the README—the README mentions 'Supports easing function' but no example code or EasingFunction enum documentation is visible in the file list
⭐Top contributors
Click to expand
Top contributors
- @shoheiyokoyama — 81 commits
- @Ezra-Black — 1 commits
- @kornerr — 1 commits
- @rinov — 1 commits
- @ziishaned — 1 commits
📝Recent commits
Click to expand
Recent commits
a9397cb— Merge pull request #39 from shoheiyokoyama/codex/fix-typos-in-animationlistviewcontroller (shoheiyokoyama)d61d6b2— Fix pitch typo in animation titles (shoheiyokoyama)b2fdff6— Merge pull request #38 from shoheiyokoyama/codex/replace--anmation-types--with--animation-types--in-readme (shoheiyokoyama)6e8f138— Fix typo in README anchor (shoheiyokoyama)2484f5c— Merge pull request #31 from Ezra-Black/master (shoheiyokoyama)679d544— Refactored static collectionViewsize name to proper grammar. (Ezra-Black)9e39941— Update README.md (shoheiyokoyama)55a3bd8— Update README.md (shoheiyokoyama)5cb6866— Update README.md (shoheiyokoyama)8f45899— Update README.md (shoheiyokoyama)
🔒Security observations
The Gemini framework codebase appears relatively secure from a static analysis perspective. As a UI animation framework for iOS written in Swift, it has low exposure to common web vulnerabilities like SQLi, XSS, or injection attacks. No hardcoded secrets, credentials, or suspicious configuration files were detected in the file structure. Main recommendations include completing documentation, establishing a security policy, and conducting dependency audits. The framework's focused scope (scroll-based animations) limits attack surface area, and Swift's type safety provides inherent security benefits over dynamic languages.
- Low · Incomplete README File —
README.md. The README.md file appears to be truncated or incomplete. The platform badge and Cocoapods badge sections are cut off mid-sentence, which may indicate missing documentation or incomplete setup instructions. Fix: Complete the README.md file with full documentation, especially security-related setup instructions and dependency information. - Low · Missing Security Policy —
Repository root. No SECURITY.md or security policy file is present in the repository to guide users on reporting security vulnerabilities or following secure development practices. Fix: Add a SECURITY.md file outlining vulnerability disclosure policy, supported versions, and contact information for security issues. - Low · Incomplete Dependency Information —
Example/Podfile and other dependency management files. The dependency/package file content was not provided for analysis. Without visibility into Podfile, Gemfile, or package.json contents, potential vulnerable dependencies cannot be fully assessed. Fix: Provide complete dependency manifest files and regularly audit dependencies using tools like CocoaPods Security Auditor or dependency-check. - Low · No License File Visible —
Repository root. While not a direct security issue, the absence of a LICENSE file in the provided file structure may indicate unclear intellectual property and usage rights. Fix: Add a LICENSE file to clarify terms of use and intellectual property rights.
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.