cbpowell/MarqueeLabel
A drop-in replacement for UILabel, which automatically adds a scrolling marquee effect when the label's text does not fit inside the specified frame
Slowing — last commit 8mo ago
worst of 4 axesno tests detected; no CI workflows detected
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
last commit was 8mo ago; no CI workflows detected
- ✓Last commit 8mo ago
- ✓14 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ⚠Slowing — last commit 8mo ago
- ⚠Single-maintainer risk — top contributor 85% of recent commits
- ⚠No CI workflows detected
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Mixed → Healthy if: add a test suite
- →Deploy as-is Mixed → Healthy if: 1 commit in the last 180 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/cbpowell/marqueelabel)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/cbpowell/marqueelabel on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: cbpowell/MarqueeLabel
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/cbpowell/MarqueeLabel 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 — Slowing — last commit 8mo ago
- Last commit 8mo ago
- 14 active contributors
- MIT licensed
- ⚠ Slowing — last commit 8mo ago
- ⚠ Single-maintainer risk — top contributor 85% of recent commits
- ⚠ No CI workflows detected
- ⚠ 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 cbpowell/MarqueeLabel
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/cbpowell/MarqueeLabel.
What it runs against: a local clone of cbpowell/MarqueeLabel — 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 cbpowell/MarqueeLabel | 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 ≤ 269 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of cbpowell/MarqueeLabel. If you don't
# have one yet, run these first:
#
# git clone https://github.com/cbpowell/MarqueeLabel.git
# cd MarqueeLabel
#
# 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 cbpowell/MarqueeLabel and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "cbpowell/MarqueeLabel(\\.git)?\\b" \\
&& ok "origin remote is cbpowell/MarqueeLabel" \\
|| miss "origin remote is not cbpowell/MarqueeLabel (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 "Sources/MarqueeLabel.swift" \\
&& ok "Sources/MarqueeLabel.swift" \\
|| miss "missing critical file: Sources/MarqueeLabel.swift"
test -f "MarqueeLabel/MarqueeLabelDemoViewController.swift" \\
&& ok "MarqueeLabel/MarqueeLabelDemoViewController.swift" \\
|| miss "missing critical file: MarqueeLabel/MarqueeLabelDemoViewController.swift"
test -f "MarqueeLabel/MarqueeLabelTableViewController.swift" \\
&& ok "MarqueeLabel/MarqueeLabelTableViewController.swift" \\
|| miss "missing critical file: MarqueeLabel/MarqueeLabelTableViewController.swift"
test -f "MarqueeLabel.podspec" \\
&& ok "MarqueeLabel.podspec" \\
|| miss "missing critical file: MarqueeLabel.podspec"
test -f "Extras/NoReturnAnimation.swift" \\
&& ok "Extras/NoReturnAnimation.swift" \\
|| miss "missing critical file: Extras/NoReturnAnimation.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 269 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~239d)"
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/cbpowell/MarqueeLabel"
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
MarqueeLabel is a Swift UILabel subclass that automatically applies a scrolling marquee (ticker) animation when text exceeds the label's frame width. It seamlessly replaces UILabel with zero behavioral changes for text that fits, while adding smooth horizontal scrolling for overflow text—commonly used for song titles, news tickers, and long status messages in iOS/tvOS apps. Dual-target monorepo: MarqueeLabel/ contains the main iOS demo app with demo controllers (MarqueeLabelDemoViewController.swift, MarqueeLabelTableViewController.swift), MarqueeLabelTV/ contains tvOS demo variant, Sources/ (inferred) holds core MarqueeLabel.swift, and Extras/ contains optional extensions (NoReturnAnimation.swift, SingleShotOffscreenLabel.swift). Built via CocoaPods with .podspec and xcworkspace coordination.
👥Who it's for
iOS and tvOS developers who need to display long, dynamically-sized text in fixed-width UI elements (navigation bars, table cells, status displays) without truncating or cutting off content. Specifically those seeking a drop-in UILabel replacement that handles overflow gracefully without custom view composition.
🌱Maturity & risk
Production-ready and stable. The codebase is well-established (118K+ lines of Swift), has been maintained actively through multiple major versions (currently at 4.0+), supports modern Swift 5.0+ with iOS 12.2+ SDK, and is distributed via CocoaPods and Carthage. However, the transition to Swift-only maintenance (v4.0+) signals maturity over active feature expansion.
Low risk for new adoption. Single maintainer (cbpowell) is a known pattern in Swift community libraries. The codebase has minimal external dependencies (only QuartzCore.framework), is well-documented inline in Sources/MarqueeLabel.swift, and the API is stable post-4.0. Main risks: no visible GitHub Actions CI pipeline in file list, and Swift-only commitment means Objective-C projects cannot use it.
Active areas of work
No current active development visible from file structure; the repository appears in maintenance mode post-4.0 Swift-only release. The CHANGELOG and versioning indicate periodic updates, but no open PRs or active branches are evident from the provided file list. Contributions likely focus on bug fixes and compatibility rather than new marquee animation types.
🚀Get running
git clone https://github.com/cbpowell/MarqueeLabel.git
cd MarqueeLabel
open MarqueeLabel.xcworkspace
# In Xcode: select MarqueeLabel scheme, build & run on iOS simulator
# or MarqueeLabelTV scheme for tvOS
No npm/Ruby dependencies to install; uses CocoaPods for distribution only (already resolved in .xcworkspace).
Daily commands:
Open MarqueeLabel.xcworkspace in Xcode, select the MarqueeLabel scheme (iOS) or MarqueeLabelTV scheme (tvOS), and press Cmd+R to build and run on the simulator. The demo app shows multiple marquee configurations in a UITableView with various text lengths and animation speeds.
🗺️Map of the codebase
Sources/MarqueeLabel.swift— Core UILabel subclass implementing marquee animation logic; every contributor must understand the animation state machine and CABasicAnimation integration.MarqueeLabel/MarqueeLabelDemoViewController.swift— Primary iOS demo implementation showing all animation modes and configuration options; reference for expected API usage patterns.MarqueeLabel/MarqueeLabelTableViewController.swift— Demonstrates integration with UITableView and cell reuse; critical for understanding lifecycle and performance constraints.MarqueeLabel.podspec— Defines module structure, Swift version requirements, and deployment targets; essential for understanding platform compatibility.Extras/NoReturnAnimation.swift— Swift-only extension pattern for custom animation variants; shows how to extend MarqueeLabel without modifying core.
🧩Components & responsibilities
- MarqueeLabel (Core Class) (UILabel, CABasicAnimation, CALayer, UIFont metrics) — Subclass of UILabel that automatically detects text overflow and initiates marquee animation; manages animation state (enabled, running, paused)
- Failure mode: Text does not scroll or animation stutters if frame width is 0, text size calculation fails, or animation is not re-added to layer after CATransaction
- Animation State Machine (CABasicAnimation, CAMediaTimingFunction, CFTimeInterval) — Tracks marquee state through properties (labyrinthineAxis, animationCurve, rate) and methods (restartLabel, pauseLabel, resumeLabel); coordinates animation lifecycle
- Failure mode: Animation does not restart properly if pauseLabel() leaves animation attached; infinite loops if repeatCount not set; race conditions if text changes during animation
- Text Measurement & Layout (NSString.size(withAttributes:), UIFont metrics, CGSize) — Calculates text width for overflow detection and animation duration; handles font size changes and multi-line text (clips to single line)
- Failure mode: Incorrect animation duration if text width calculation uses wrong font; animation triggers incorrectly if label frame is set before text
- Demo Controllers (iOS/tvOS) (UIViewController, UITableView, IBOutlet, Storyboard) — Instantiate MarqueeLabel with various configurations; demonstrate animation modes, rate adjustments, and integration patterns (table view, storyboard)
- Failure mode: Demo crashes if MarqueeLabel not properly initialized with frame; table cell reuse leaks animations if restartLabel() not called in prepareForReuse()
🔀Data flow
UIViewController / Storyboard→MarqueeLabel Instance— Text string and frame geometry are set via properties or IBOutlets; MarqueeLabel observes text changes and triggers overflow detectionMarqueeLabel→CABasicAnimation— Constructs animation parameters (duration = textWidth / rate, fromValue = 0, toValue = -textWidth) and adds to layerCABasicAnimation→CALayer (text rendering)— Core Animation updates layer.position.x on each frame (~16.7ms at 60fps); position change shifts text horizontally for scroll effectMarqueeLabel→UIView.layer.mask—
🛠️How to make changes
Add a Custom Animation Mode
- Open Sources/MarqueeLabel.swift and locate the animation setup in the drawsMarquee() method (
Sources/MarqueeLabel.swift) - Create a new animationSpeed or rate configuration property following the pattern of labyrinthine, leftRight, rightLeft modes (
Sources/MarqueeLabel.swift) - Implement CABasicAnimation with custom fromValue/toValue and duration based on new mode (
Sources/MarqueeLabel.swift) - Test integration in MarqueeLabelDemoViewController.swift by creating a new label instance with the custom mode (
MarqueeLabel/MarqueeLabelDemoViewController.swift)
Integrate MarqueeLabel into a Table View
- Study existing implementation in MarqueeLabelTableViewController.swift for cell reuse lifecycle (
MarqueeLabel/MarqueeLabelTableViewController.swift) - Create MarqueeLabel instances in tableView(_:cellForRowAt:) with explicit frame and text assignment (
MarqueeLabel/MarqueeLabelTableViewController.swift) - Call restartLabel() on reused cells and manage animation state in prepareForReuse() (
Sources/MarqueeLabel.swift) - Configure rate and animationDelay properties to avoid overlapping scroll animations across visible cells (
MarqueeLabel/MarqueeLabelTableViewController.swift)
Create a Custom Animation Variant
- Use the Extras/NoReturnAnimation.swift pattern as template for extension (
Extras/NoReturnAnimation.swift) - Extend MarqueeLabel with a new computed property or method that modifies animation properties (duration, timingFunction, repeatCount) (
Extras/NoReturnAnimation.swift) - Test the variant by instantiating in Extras/SingleShotOffscreenLabel.swift or a demo controller (
Extras/SingleShotOffscreenLabel.swift)
🔧Why these technologies
- CABasicAnimation (Core Animation) — Provides smooth, GPU-accelerated scrolling with precise timing control; essential for marquee effect at 60fps without blocking main thread
- UILabel subclass — Drop-in replacement pattern allows existing UILabel code to work unchanged; leverages text rendering, font metrics, and layout compatibility
- Swift (Swift-only from 4.0+) — Modern language features (properties, computed values, extensions) reduce boilerplate; cleaner animation state management than Objective-C
- CocoaPods packaging — Enables easy integration into iOS projects; supports both iOS and tvOS platforms through podspec configuration
⚖️Trade-offs already made
-
Swift-only (dropped Objective-C support in 4.0+)
- Why: Reduces maintenance burden and simplifies codebase; forces adoption of modern Swift features
- Consequence: Legacy Objective-C projects must either upgrade to Swift or use older MarqueeLabel versions
-
UILabel subclass rather than composition
- Why: Provides true drop-in replacement with all UILabel properties; simpler integration for existing apps
- Consequence: Inherits UILabel limitations (single-line focus); harder to extend with new text rendering behaviors
-
CABasicAnimation instead of UIView.animate()
- Why: Finer control over animation properties (repeat count, easing, explicit layer positioning)
- Consequence: Requires direct Core Animation layer management; must handle animation lifecycle explicitly (start/stop/restart)
-
Manual text width calculation for duration
- Why: Allows user-configurable rate (points/second) independent of text length
- Consequence: Must handle font size changes and text updates by recalculating; potential performance cost for frequent updates
🚫Non-goals (don't propose these)
- Does not support multi-line marquee; operates on single-line labels only
- Does not handle RTL (right-to-left) languages natively
- Not a text layout engine; relies entirely on UILabel's text rendering
- Does not provide built-in accessibility features beyond standard UILabel
- Not designed for real-time data feeds; animation restarts require explicit restartLabel() call
🪤Traps & gotchas
No visible unit tests in file list—test coverage is unclear; integrate with CI/XCTest yourself. Single-threaded UI assumption: animation happens on main thread only; long text preprocessing may stall UI. Frame-dependent initialization: marquee behavior depends on label frame being set before text assignment, or label must be added to view hierarchy; setting text in init() with auto-layout may not trigger scrolling until layout pass. XCode 12+ required: Swift 5.0+ support means no pre-iOS 12.2 deployments. Edge fade uses CAGradientLayer: can conflict with custom layer rendering or mask-based clipping in parent views.
🏗️Architecture
💡Concepts to learn
- Core Animation (CABasicAnimation) — MarqueeLabel's entire scrolling effect is built on CABasicAnimation for the text position; understanding bezier curves, timing functions (linear/ease), and transform animations is essential to customizing scroll behavior
- CAGradientLayer masking for edge fade — The optional edge-fade feature (fading text at left/right edges) uses CAGradientLayer as a mask; critical to understand alpha blending and layer compositing to modify or debug fade behavior
- NSString text measurement and sizing — MarqueeLabel determines whether to scroll by measuring text size relative to frame width; UIKit's
boundingRect(with:)and font metrics directly trigger animation logic, so sizing precision affects scroll activation - UILabel subclassing and property overrides — MarqueeLabel overrides critical UILabel properties (
text,font,frame) to maintain animation state; understanding KVO, property observers, and layout lifecycle is needed to extend or debug integration issues - Timer-based animation scheduling vs. CADisplayLink — MarqueeLabel likely uses Timer or dispatch for scroll state updates; choosing between Timer (UI-thread blocking) and CADisplayLink (vsync-synced) affects frame smoothness and CPU usage—visible in animation smoothness tuning
- View hierarchy and layout constraints (Auto Layout) — Marquee behavior depends on final frame size, which is determined by Auto Layout; misunderstanding constraint resolution timing vs. text-assignment timing is a common integration trap in the codebase
- Right-to-left (RTL) text layout — MarqueeLabel must handle Arabic, Hebrew, and other RTL languages; scroll direction and text measurement differ in RTL contexts, affecting animation direction and edge-fade placement—likely an untested edge case
🔗Related repos
cbpowell/MarqueeLabel— This is the primary repo itself; listed for reference as the canonical sourceopentick/TickerView— Alternative iOS ticker/scrolling text view using CADisplayLink for smoother custom animations; good comparison for different animation scheduling approachesrealm/SwiftLint— Swift linting tool; useful for maintaining code quality in MarqueeLabel contributions and ensuring consistent Swift style across the 118K-line codebasepointfreeco/swift-composable-architecture— Modern Swift architecture pattern; relevant for developers integrating MarqueeLabel into TCA-based iOS apps or extending marquee state managementsocketio/socket.io-client-swift— Real-time data push library; common pairing for apps that display live-updating ticker data (stock prices, sports scores) using MarqueeLabel
🪄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 for Swift/iOS testing
The repo lacks automated CI/CD for running tests on pull requests. While there's a .github/FUNDING.yml, there are no workflow files (.github/workflows) for building, testing, and linting Swift code. This would catch regressions early and ensure code quality across iOS and tvOS targets.
- [ ] Create .github/workflows/swift-ci.yml with build steps for MarqueeLabel.xcworkspace using xcodebuild
- [ ] Configure separate build schemes for iOS (MarqueeLabel) and tvOS (MarqueeLabelTV) targets
- [ ] Add Swift lint step (SwiftLint) to enforce code style consistency
- [ ] Test against multiple Swift/iOS SDK versions (5.0+) as mentioned in README compatibility
Create comprehensive unit tests for MarqueeLabel core functionality
The repo has demo apps (MarqueeLabelDemoViewController.swift, MarqueeLabelTableViewController.swift) but no visible Test or Tests directory with unit tests for the core MarqueeLabel class behavior. Key animations and label behavior need test coverage.
- [ ] Create Tests/ directory with MarqueeLabelTests.swift
- [ ] Add tests for marquee animation triggering (text overflow detection)
- [ ] Add tests for scroll direction properties and animation speed/rate configuration
- [ ] Add tests for UILabel property compatibility (text, font, textColor, etc.)
- [ ] Add snapshot or rendering tests for both iOS and tvOS scroll behavior
Document public API and properties in README with usage examples
The README.md mentions high-level features and that code exists in Extras/ (NoReturnAnimation.swift, SingleShotOffscreenLabel.swift) but lacks specific API documentation and code examples. New contributors need clearer guidance on customizable properties like scrolling direction, speed, animation type, and when to use the Extras.
- [ ] Add 'Installation' section with CocoaPods (MarqueeLabel.podspec exists) and Swift Package Manager instructions
- [ ] Add 'Basic Usage' section with code example showing initialization, text assignment, and frame setup
- [ ] Document key properties: marqueeType, speed, rate, animationCurve, fadeLength with example values
- [ ] Add 'Advanced Usage' section explaining when/how to use Extras/NoReturnAnimation.swift and Extras/SingleShotOffscreenLabel.swift
- [ ] Include tvOS-specific considerations since the repo supports both iOS and tvOS
🌿Good first issues
- Add XCTest unit tests for core MarqueeLabel functionality: File list shows no tests/ or Tests/ directory; create test targets for animations, text measurement, scroll-trigger logic, and edge cases (empty text, single-char labels, RTL text)
- Document the marquee timing formula and speed calculation in inline code comments: Sources/MarqueeLabel.swift is 118K lines but rate/duration math for scroll distance calculation is not obviously explained; add comments showing how
pointsPerSecondconverts toCABasicAnimationduration - Create Swift Package Manager (SPM) manifest (Package.swift) alongside CocoaPods/Carthage: Modern Swift projects use SPM; no Package.swift visible in file list, blocking adoption in SPM-only projects; add minimal manifest with iOS 12.2+ target
⭐Top contributors
Click to expand
Top contributors
- @cbpowell — 85 commits
- @eric — 2 commits
- [@Aleksandra Generowicz](https://github.com/Aleksandra Generowicz) — 2 commits
- @KaiOelfke — 1 commits
- @yujinakayama — 1 commits
📝Recent commits
Click to expand
Recent commits
c6b4da4— Switch debugging flag to be MarqueeLabel-specific (cbpowell)739f665— Bump podspec (cbpowell)85d9bdf— Project upgrade, remove debug flag for demo (cbpowell)bfc25ba— Improve trailingView debug view usefulness on continuous types (cbpowell)350baa7— Add more debugging features (cbpowell)eca72d1— Add visual debugging option for leading/trailing buffer sizing (cbpowell)82a75bd— Adjust origin location for animation (cbpowell)7dff93c— Adapt to using a (0.5,0.5) default position value for the sublabel layer, relative to #301 issues (cbpowell)13ea081— Bump podspec version (cbpowell)47173b2— Merge pull request #300 from KaiOelfke/spm-bump-supported-platforms (cbpowell)
🔒Security observations
MarqueeLabel is a UILabel subclass library for iOS/tvOS with minimal security surface area. No critical vulnerabilities detected. The codebase is a UI component library written in Swift with no backend services, databases, external APIs, or complex dependencies that would typically introduce security risks. Minor recommendations focus on general best practices for dependency management and code review processes.
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.