rechsteiner/Parchment
A paging view with a highly customizable menu ✨
Stale — last commit 2y ago
worst of 4 axeslast commit was 2y ago; top contributor handles 92% of recent commits…
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.
- ✓6 active contributors
- ✓MIT licensed
- ✓CI configured
Show 3 more →Show less
- ⚠Stale — last commit 2y ago
- ⚠Single-maintainer risk — top contributor 92% of recent commits
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: 1 commit in the last 365 days; diversify commit ownership (top <90%)
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/rechsteiner/parchment)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/rechsteiner/parchment on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: rechsteiner/Parchment
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/rechsteiner/Parchment 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 2y ago
- 6 active contributors
- MIT licensed
- CI configured
- ⚠ Stale — last commit 2y ago
- ⚠ Single-maintainer risk — top contributor 92% of recent commits
- ⚠ 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 rechsteiner/Parchment
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/rechsteiner/Parchment.
What it runs against: a local clone of rechsteiner/Parchment — 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 rechsteiner/Parchment | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 618 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of rechsteiner/Parchment. If you don't
# have one yet, run these first:
#
# git clone https://github.com/rechsteiner/Parchment.git
# cd Parchment
#
# 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 rechsteiner/Parchment and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "rechsteiner/Parchment(\\.git)?\\b" \\
&& ok "origin remote is rechsteiner/Parchment" \\
|| miss "origin remote is not rechsteiner/Parchment (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 main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "Parchment/ParchmentViewController.swift" \\
&& ok "Parchment/ParchmentViewController.swift" \\
|| miss "missing critical file: Parchment/ParchmentViewController.swift"
test -f "Parchment/Structs/ParchmentViewController+DataSource.swift" \\
&& ok "Parchment/Structs/ParchmentViewController+DataSource.swift" \\
|| miss "missing critical file: Parchment/Structs/ParchmentViewController+DataSource.swift"
test -f "Parchment/Views/ParchmentCollectionView.swift" \\
&& ok "Parchment/Views/ParchmentCollectionView.swift" \\
|| miss "missing critical file: Parchment/Views/ParchmentCollectionView.swift"
test -f "Parchment/Structs/ParchmentViewControllerConfig.swift" \\
&& ok "Parchment/Structs/ParchmentViewControllerConfig.swift" \\
|| miss "missing critical file: Parchment/Structs/ParchmentViewControllerConfig.swift"
test -f "Example/ExamplesViewController.swift" \\
&& ok "Example/ExamplesViewController.swift" \\
|| miss "missing critical file: Example/ExamplesViewController.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 618 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~588d)"
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/rechsteiner/Parchment"
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
Parchment is a Swift UIKit framework that implements a customizable horizontal paging view controller with a scrollable menu indicator. It uses UICollectionView for the menu UI, allowing developers to page through view controllers (or SwiftUI views) while displaying synchronized menu items—supporting infinite scrolling for use cases like calendars where data sources can be dynamically loaded. Single-package structure: Parchment/ contains the core UICollectionView-based paging logic; Example/ contains 11 runnable demo implementations (Basic, Calendar, Icons, Images, Wheel, etc.) showing different customization patterns; Documentation/ holds usage guides for DataSource and InfiniteDataSource patterns. SwiftUI support was added later as a wrapper layer.
👥Who it's for
iOS developers building tabbed/paged navigation interfaces (e.g., photo galleries, calendar apps, news readers, category browsers) who need a more flexible and memory-efficient alternative to UIPageViewController with a synchronized, customizable menu bar.
🌱Maturity & risk
Production-ready. The repo shows 503K lines of Swift code, has CI/CD via GitHub Actions (.github/workflows/parchment.yml), comprehensive documentation in Documentation/, and 11 distinct example implementations. Commit recency and issue activity suggest active maintenance, though single-maintainer (rechsteiner) creates some long-term risk.
Low-to-moderate risk. Single maintainer (rechsteiner) is the primary concern for long-term support. No obvious dependency bloat visible in the structure. Breaking changes are possible between major versions (see CHANGELOG.md), so version pinning is recommended for stability. UIKit dependency means it won't work with SwiftUI-only projects without bridging.
Active areas of work
Active development with SwiftUI support (mentioned in README). The file structure shows recent additions like Examples/LargeTitles, Examples/SelfSizing, and SizeDelegate patterns. The CHANGELOG.md and Documentation/ suggest iterative feature additions and API refinement rather than bug-fix mode.
🚀Get running
git clone https://github.com/rechsteiner/Parchment.git && cd Parchment && open Parchment.xcodeproj. For SwiftPM: .swiftpm/xcode/package.xcworkspace is configured. Run Example/AppDelegate.swift schemes to see 11 pre-built examples.
Daily commands: Xcode project: open Parchment.xcodeproj, select Example scheme, Cmd+R. SwiftPM: xcode -o Package.xcworkspace and open .swiftpm/xcode/package.xcworkspace. Both reveal 11 runnable examples in Example/Examples/*/.
🗺️Map of the codebase
Parchment/ParchmentViewController.swift— Core view controller managing the paging view and menu synchronization; all contributors must understand this entry pointParchment/Structs/ParchmentViewController+DataSource.swift— Defines the data source protocol that bridges menu items to paged content; essential for understanding how data flows into ParchmentParchment/Views/ParchmentCollectionView.swift— UICollectionView subclass managing the menu rendering and layout; critical for customization patternsParchment/Structs/ParchmentViewControllerConfig.swift— Configuration struct holding all customizable properties; every feature flag and styling option passes through hereExample/ExamplesViewController.swift— Comprehensive example selector showing all major patterns and use cases in this repoDocumentation/basic-usage.md— Primary onboarding document explaining foundational concepts and integration steps.swift-version— Specifies minimum Swift version requirement; essential for build compatibility across team
🧩Components & responsibilities
- ParchmentViewController (UIViewController, UIPageViewController, Delegation) — Orchestrates UIPageViewController and menu CollectionView; synchronizes bidirectional paging and menu selection
- Failure mode: Pages and menu fall out of sync if scroll delegates are not properly managed; can cause race conditions
- ParchmentCollectionView (Menu) (UICollectionView, UICollectionViewFlowLayout) — Renders horizontal menu items with automatic scroll-to-fit-visible logic
- Failure mode: Menu items may fail to center or scroll if custom cell sizes are not properly reported
- DataSource Protocol (Protocol, Generics) — Bridge between host app data and Parchment; provides menu items and child view controllers on-demand
- Failure mode: Incorrect item count or ViewController mismatch causes index out of bounds or blank pages
- PagingCell (UICollectionViewCell, CALayer animations) — Base template for menu items; styled with colors, fonts, and indicator styling from PagingCellAppearance
- Failure mode: Custom subclasses may not respect appearance settings if configureCell() is not called properly
🔀Data flow
Host App→ParchmentViewController— Provides dataSource conforming to ParchmentDataSource protocol; defines numberOfItems and viewControllerAtIndexParchmentViewController→UIPageViewController— Requests view controllers from dataSource and sets them as
🛠️How to make changes
Add a new custom menu item style
- Create a new PagingItem subclass in Parchment/Models/ that defines your custom data (e.g., icon, badge count) (
Parchment/Models/PagingItem.swift) - Create a custom UICollectionViewCell subclass in Parchment/Cells/ that inherits from PagingCell and overrides configureCell() (
Parchment/Cells/PagingCell.swift) - In your view controller, override registerCollectionViewCells() and register your custom cell class (
Parchment/ParchmentViewController.swift) - Override collectionView(_:cellForItemAt:) to return your custom cell and configure it with your item data (
Parchment/ParchmentViewController.swift) - Optionally implement sizeDelegate() callback to return custom sizing for your cell (
Parchment/Structs/ParchmentViewController+Delegate.swift)
Implement a basic paging view
- Create a view controller and add ParchmentViewController as a child, constraining it to your view (
Example/Examples/Basic/BasicViewController.swift) - Create a data model conforming to ParchmentDataSource with numberOfItems and viewControllerAtIndex methods (
Parchment/Structs/ParchmentViewController+DataSource.swift) - Set dataSource on your ParchmentViewController instance and call reloadData() (
Parchment/ParchmentViewController.swift)
Add infinite scroll pagination
- Implement ParchmentDataSource with a dynamic items array that grows as needed (
Documentation/infinite-data-source.md) - Override willScroll(toPagingItem:) delegate method to detect near-end scrolling (
Parchment/Structs/ParchmentViewController+Delegate.swift) - Fetch new items asynchronously and call reloadData() or insertItems() to update the menu (
Example/Examples/Images/ImagesViewController.swift)
🔧Why these technologies
- UIPageViewController — Standard iOS framework for swipeable page navigation with built-in gesture handling and native page transition animations
- UICollectionView — Provides flexible menu rendering with automatic scrolling, cell reuse, and customizable layouts (horizontal flow)
- Swift / iOS SDK — Native iOS framework integration; Parchment is a pure UIKit wrapper library with no external dependencies
⚖️Trade-offs already made
-
UIPageViewController instead of custom UIScrollView pagination
- Why: Leverages Apple's native, well-tested paging controller with built-in gesture recognizers and transition animations
- Consequence: Limited control over transition timing and mechanics; harder to implement non-standard animations like 3D flip or cover flow
-
Bidirectional synchronization between menu and pages (both trigger each other)
- Why: Provides seamless UX where tapping menu scrolls pages and swiping pages scrolls menu automatically
- Consequence: Complex state management required to prevent feedback loops; careful coordination of scroll delegates needed
-
DataSource protocol instead of Diffable DataSource (iOS 13+)
- Why: Maintains backward compatibility with older iOS versions and simpler API for simpler use cases
- Consequence: Manual reloadData() calls required; less efficient diffing and slower updates for large datasets
🚫Non-goals (don't propose these)
- Real-time synchronization with network events
- Persistence of scroll position or page state across app launches
- Support for vertical or grid-based menu layouts (horizontal-only)
- Accessibility features like VoiceOver deep integration
- Android or cross-platform support
🪤Traps & gotchas
- InfiniteDataSource requires centering logic: Calendar example uses centering to allow scrolling in both directions infinitely; raw data source doesn't handle this automatically. 2. Memory management in closures: PagingViewController retains delegates/data sources; circular references possible if view controller holds reference back. 3. Custom cells must manage selection state: IconPagingCell example shows selectedItem must be explicitly tracked; default UICollectionViewCell selection styling won't work. 4. SwiftUI integration is a wrapper: Native SwiftUI support wraps UIKit underneath; deep customization may require dropping to UIKit layer.
🏗️Architecture
💡Concepts to learn
- UICollectionView Dynamic Layout — Parchment's menu is entirely UICollectionView-based rather than manual UIStackView/UIView composition; understanding collection view layouts (PagingCollectionViewLayout) is essential to customizing indicator behavior and menu sizing.
- Lazy View Controller Instantiation — Core efficiency feature: view controllers are allocated only when scrolled into view via DataSource pattern, enabling unbounded paging (infinite calendars). This differs from UIPageViewController which often pre-allocates.
- Delegate Pattern for Customization — Parchment exposes PagingViewControllerDelegate and PagingSizeDelegate protocols rather than subclassing; this allows composable customization without deep inheritance hierarchies and is idiomatic Swift.
- Synchronized Scroll Indicators — The menu bar indicator moves continuously as the page view scrolls, requiring real-time sync between scroll offset and layout invalidation; PagingCollectionViewLayout handles this via scroll delegate callbacks.
- Infinite Data Sources — Parchment's InfiniteDataSource pattern supports unbounded datasets by using a centering offset technique (visible in CalendarViewController); allows calendars to scroll infinitely in past/future without pre-loading all data.
- Container View Controller Pattern — PagingViewController acts as a container managing multiple child view controllers and their lifecycle (addChild, willMove, removeFromParent); essential for understanding iOS ViewController containment APIs.
- SwiftUI-UIKit Bridging — Parchment wraps UIKit PagingViewController in a SwiftUI PageView component; shows patterns for UIViewControllerRepresentable and state synchronization across frameworks.
🔗Related repos
kickstarter/ios-oss— Large production iOS app using Parchment for tabbed navigation; shows real-world integration patternsuias/Tabman— Competing Swift paging library with similar menu-sync design; reference for feature parity and architectural decisionspagerduty/ios-sdk— Depends on Parchment for account switching tabs; demonstrates ecosystem adoptionrechsteiner/SwiftUI-Navigation— Same maintainer's SwiftUI navigation patterns; complements Parchment's SwiftUI wrapper layer
🪄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 comprehensive unit tests for ParchmentViewController core functionality
The repo has no visible test files despite containing a complex UIViewController subclass. Given the variety of examples (Calendar, Icons, Images, Wheel, etc.), there should be unit tests covering data source interactions, menu updates, and page transitions. This would prevent regressions and help new contributors understand the API.
- [ ] Create Tests/ directory structure mirroring Parchment/ source layout
- [ ] Add tests for ParchmentViewController initialization, data source delegation, and menu item selection
- [ ] Add tests for infinite data source behavior (referenced in Documentation/infinite-data-source.md)
- [ ] Add tests for menu customization (sizing, appearance, scrolling behavior)
- [ ] Integrate tests into .github/workflows/parchment.yml CI pipeline
Add iOS 17+ support documentation and SwiftUI example
The repo has extensive UIKit examples but no documentation about iOS version support or SwiftUI integration. The .swift-version file and CHANGELOG.md exist but SwiftUI adoption is increasingly important. A new example showing ParchmentViewController wrapped in UIViewControllerRepresentable would be valuable.
- [ ] Create Example/Examples/SwiftUI/SwiftUIParchmentExample.swift demonstrating UIViewControllerRepresentable wrapper
- [ ] Update Documentation/basic-usage.md with minimum iOS version requirements and iOS 17+ considerations
- [ ] Add a SwiftUI integration section to Documentation/ (e.g., Documentation/swiftui-integration.md)
- [ ] Test and document any differences in behavior between iOS versions in CHANGELOG.md
Extract and document common pagination patterns from existing examples
The Example/ folder has 12+ example ViewControllers but no guide documenting common patterns (infinite scrolling, dynamic sizing, custom menu styling). Creating a patterns guide would help maintainers review similar PRs consistently and help contributors avoid duplicating code.
- [ ] Analyze CalendarViewController, UnsplashViewController, and WheelViewController for shared patterns
- [ ] Create Documentation/common-patterns.md covering: infinite data sources, self-sizing cells, custom menu styling, and header integration
- [ ] Document the differences between SizeDelegateViewController and SelfSizingViewController approaches
- [ ] Add code snippets and links to relevant example files for each pattern
🌿Good first issues
- Add unit tests for PagingCollectionViewLayout scroll-sync behavior. The layout manager is tested only implicitly via example apps; add test suite in Tests/Layouts/ covering indicator movement on scroll at different menu sizes.: Core visual behavior lacks isolated tests, making refactoring risky.
- Document SizeDelegateViewController pattern in Documentation/. Example/Examples/SizeDelegate/ exists but is not mentioned in README or Documentation/; add guide explaining dynamic menu sizing use cases and implementation.: Example code exists but discoverable documentation is missing; creates friction for size-customization use case.
- Add support for vertical paging orientation. Current code assumes horizontal paging (PagingCollectionViewLayout assumes UICollectionViewScrollDirectionHorizontal). Extend to support vertical layouts like Pinterest-style feeds.: Natural feature request visible from architecture; opens new use case without large refactor.
⭐Top contributors
Click to expand
Top contributors
- @rechsteiner — 92 commits
- @aiKrice — 3 commits
- @kitwtnb — 2 commits
- @nfgrilo — 1 commits
- @rono23 — 1 commits
📝Recent commits
Click to expand
Recent commits
dfb23ea— Fix Swift version in podspec (rechsteiner)c818d07— Merge pull request #733 from rechsteiner/release (rechsteiner)eaf53bc— Release v4.1.0 (rechsteiner)c3aab6d— Merge pull request #731 from rechsteiner/actions (rechsteiner)7799b0f— Update build server to Xcode 16 (rechsteiner)2e3283e— Merge pull request #723 from rechsteiner/swift-6 (rechsteiner)7190374— Fix isolation errors in UI tests (rechsteiner)2e5981d— Rewrite tests to new swift-testing framework (rechsteiner)5d7ed95— Make properties in layout attributes subclasses nonisolated (rechsteiner)e224f4a— Update Github runner to macOS 14 and Xcode 16 beta (rechsteiner)
🔒Security observations
The Parchment iOS UI framework shows a reasonable security posture with no obvious critical vulnerabilities visible in the file structure. The codebase is an example/demo project without apparent hardcoded credentials, injection vulnerabilities, or exposed sensitive data. However, the analysis is limited by the unavailability of Package.swift contents, making dependency vulnerability assessment impossible. The project would benefit from explicit security policies, automated dependency scanning, and documented vulnerability reporting procedures. No Docker or infrastructure misconfigurations are evident in the provided file listing.
- Low · Missing Package Dependency File —
Package.swift (root directory). The Package.swift manifest file is not provided in the analysis. Without examining the declared dependencies, it's impossible to verify if the project uses outdated, vulnerable, or unvetted third-party packages. The 'Dependencies/Package file content:' section is empty. Fix: Provide Package.swift contents for analysis. Regularly audit dependencies using tools likeswift package diagnoseand keep all packages updated to their latest secure versions. - Low · No Security Configuration Files Detected —
Repository root. The repository lacks visible security configuration files such as SECURITY.md, .dependabot, or code scanning configuration beyond basic CI/CD workflows. This may indicate incomplete security practices. Fix: Add a SECURITY.md file documenting vulnerability reporting procedures. Enable GitHub's Dependabot for automatic dependency updates and security alerts. Configure CodeQL scanning in GitHub Actions. - Low · Limited CI/CD Security Hardening Evidence —
.github/workflows/parchment.yml. Only one GitHub Actions workflow file is visible (parchment.yml). Without reviewing its contents, potential security gaps in CI/CD pipeline hardening cannot be assessed (e.g., insufficient secrets management, missing workflow permissions scope). Fix: Review and implement GitHub Actions security best practices: use least privilege permissions, pin action versions, rotate secrets regularly, and enable branch protection rules.
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.