RepoPilotOpen in app →

cgoldsby/LoginCritter

An animated avatar that responds to text field interactions

Mixed

Stale — last commit 6y ago

worst of 4 axes
Use as dependencyConcerns

last commit was 6y ago; top contributor handles 94% of recent commits…

Fork & modifyMixed

no tests detected; no CI workflows detected…

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 6y ago; no CI workflows detected

  • 4 active contributors
  • MIT licensed
  • Stale — last commit 6y ago
Show 4 more →
  • Small team — 4 contributors active in recent commits
  • Single-maintainer risk — top contributor 94% of recent commits
  • No CI workflows detected
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: 1 commit in the last 365 days
  • Fork & modify MixedHealthy if: add a test suite
  • Deploy as-is MixedHealthy 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 "Great to learn from" badge

Paste into your README — live-updates from the latest cached analysis.

RepoPilot: Great to learn from
[![RepoPilot: Great to learn from](https://repopilot.app/api/badge/cgoldsby/logincritter?axis=learn)](https://repopilot.app/r/cgoldsby/logincritter)

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/cgoldsby/logincritter on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: cgoldsby/LoginCritter

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:

  1. 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.
  2. 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.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/cgoldsby/LoginCritter 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

  • 4 active contributors
  • MIT licensed
  • ⚠ Stale — last commit 6y ago
  • ⚠ Small team — 4 contributors active in recent commits
  • ⚠ Single-maintainer risk — top contributor 94% 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 cgoldsby/LoginCritter repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/cgoldsby/LoginCritter.

What it runs against: a local clone of cgoldsby/LoginCritter — 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 cgoldsby/LoginCritter | 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 ≤ 2366 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>cgoldsby/LoginCritter</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of cgoldsby/LoginCritter. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/cgoldsby/LoginCritter.git
#   cd LoginCritter
#
# 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 cgoldsby/LoginCritter and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "cgoldsby/LoginCritter(\\.git)?\\b" \\
  && ok "origin remote is cgoldsby/LoginCritter" \\
  || miss "origin remote is not cgoldsby/LoginCritter (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 "LoginCritter/Sources/Login/Critter/CritterView.swift" \\
  && ok "LoginCritter/Sources/Login/Critter/CritterView.swift" \\
  || miss "missing critical file: LoginCritter/Sources/Login/Critter/CritterView.swift"
test -f "LoginCritter/Sources/Login/Critter/CritterAnimatable.swift" \\
  && ok "LoginCritter/Sources/Login/Critter/CritterAnimatable.swift" \\
  || miss "missing critical file: LoginCritter/Sources/Login/Critter/CritterAnimatable.swift"
test -f "LoginCritter/Sources/Login/LoginViewController.swift" \\
  && ok "LoginCritter/Sources/Login/LoginViewController.swift" \\
  || miss "missing critical file: LoginCritter/Sources/Login/LoginViewController.swift"
test -f "LoginCritter/Sources/Helpers/CATransform3D+Helper.swift" \\
  && ok "LoginCritter/Sources/Helpers/CATransform3D+Helper.swift" \\
  || miss "missing critical file: LoginCritter/Sources/Helpers/CATransform3D+Helper.swift"
test -f "LoginCritter/Sources/Login/Critter/CritterAssets.swift" \\
  && ok "LoginCritter/Sources/Login/Critter/CritterAssets.swift" \\
  || miss "missing critical file: LoginCritter/Sources/Login/Critter/CritterAssets.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 2366 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~2336d)"
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/cgoldsby/LoginCritter"
  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).

</details>

TL;DR

LoginCritter is an iOS UIKit-based animated avatar system that responds to text field interactions in real-time, using UIPropertyAnimator to drive head rotation and multi-part body animations based on user input. The avatar is composed of vector PDF layers (body, head, eyes, ears, mouth) that transition between five distinct emotional states (neutral, active, ecstatic, shy, peek) triggered by email/password field focus and text input events. Single-target iOS app structure: LoginCritter/ contains the main Swift source, LoginCritter/Resources/Assets.xcassets/ holds all vector PDF sprite assets organized by body part (Arm.imageset, Eye.imageset, Mouth-full.imageset, etc.). State management is likely controller-based rather than Redux-style; the Gemfile suggests optional Ruby scripting for asset generation or CI, but it's not core to runtime.

👥Who it's for

iOS developers building login screens or user authentication flows who want to add engaging, character-driven UI animations without writing custom shape rendering code. Designers and engineers exploring animation techniques in UIKit who want a reference implementation of property-based animator fraction control.

🌱Maturity & risk

Experimental/educational stage: no git history or commit metadata visible in the file list, single maintainer (cgoldsby), minimal test infrastructure apparent, and no CI/CD setup detected. This appears to be a polished demo/reference project rather than a dependency intended for production use.

High single-maintainer risk with no visible active development signals (no recent commits, no open issues list provided). The codebase has no automated tests visible in the file structure, no dependency management beyond standard Xcode, and relies entirely on manual animation tuning via UIPropertyAnimator fraction values—changes to layout or screen size could break carefully-calibrated animation math.

Active areas of work

No active development signals visible in the provided file list—no recent commits, open PRs, or milestones mentioned. This appears to be a stable, completed reference project frozen at a working state.

🚀Get running

Clone and open in Xcode 14+: git clone https://github.com/cgoldsby/LoginCritter.git && cd LoginCritter && open LoginCritter.xcodeproj. Press Cmd+R in Xcode to build and run on a simulator (iOS 13+). No CocoaPods or external package manager install step required—all dependencies are Xcode-native.

Daily commands: Open LoginCritter.xcodeproj in Xcode, select target 'LoginCritter', choose a simulator (iPhone 14 or similar), and press Cmd+R. If building for device, ensure a valid signing identity is configured in Build Settings.

🗺️Map of the codebase

  • LoginCritter/Sources/Login/Critter/CritterView.swift — Core avatar composite that assembles all body parts and orchestrates animations—the primary interface for animation state management.
  • LoginCritter/Sources/Login/Critter/CritterAnimatable.swift — Protocol defining all animation behaviors (eye tracking, mouth states, head rotation); every animation method must conform to this contract.
  • LoginCritter/Sources/Login/LoginViewController.swift — Entry point that wires text field interactions to critter animations; demonstrates the complete animation trigger flow.
  • LoginCritter/Sources/Helpers/CATransform3D+Helper.swift — 3D transformation utilities for head rotation and perspective; critical for visual fidelity of core animations.
  • LoginCritter/Sources/Login/Critter/CritterAssets.swift — Asset enumeration and loading logic; any asset changes or new body parts must be registered here.
  • LoginCritter/Sources/AppDelegate.swift — Application entry point and window setup; essential for understanding app lifecycle and root view controller initialization.

🛠️How to make changes

Add a new critter body part

  1. Create a new PDF asset in LoginCritter/Resources/Assets.xcassets/ with a unique imageset folder (LoginCritter/Resources/Assets.xcassets)
  2. Add the asset case to the CritterAssets enum (LoginCritter/Sources/Login/Critter/CritterAssets.swift)
  3. Create a new UIImageView subclass in LoginCritter/Sources/Login/Critter/Parts/ (e.g., Tail.swift) (LoginCritter/Sources/Login/Critter/Parts)
  4. Add the part to CritterView.swift initialization and layout constraints (LoginCritter/Sources/Login/Critter/CritterView.swift)
  5. Implement animation methods in the part class and optionally add protocol methods to CritterAnimatable (LoginCritter/Sources/Login/Critter/CritterAnimatable.swift)

Add a new animation state (e.g., 'shocked')

  1. Add a new case to the animation state enum (likely within CritterView or as a new enum) (LoginCritter/Sources/Login/Critter/CritterView.swift)
  2. Implement the animation logic by creating or extending methods in CritterAnimatable protocol (LoginCritter/Sources/Login/Critter/CritterAnimatable.swift)
  3. Call the new animation method from LoginViewController based on a text field event (LoginCritter/Sources/Login/LoginViewController.swift)
  4. Create corresponding mouth/eye asset variants in CritterAssets if needed (LoginCritter/Sources/Login/Critter/CritterAssets.swift)

Connect a new text field interaction trigger

  1. Add a new UITextFieldDelegate method or extend an existing one in LoginViewController (LoginCritter/Sources/Login/LoginViewController.swift)
  2. Calculate the animation parameter (e.g., fraction complete based on text width) and call the critter animation (LoginCritter/Sources/Login/LoginViewController.swift)
  3. Ensure the animation method exists in CritterView or CritterAnimatable (LoginCritter/Sources/Login/Critter/CritterView.swift)

Adjust 3D rotation or transformation behavior

  1. Review the current transformation in the relevant part class (e.g., Head.swift) (LoginCritter/Sources/Login/Critter/Parts/Head.swift)
  2. Update the helper extension or create new rotation/perspective matrices (LoginCritter/Sources/Helpers/CATransform3D+Helper.swift)
  3. Adjust Degree conversion logic if angle ranges change (LoginCritter/Sources/Helpers/Degree.swift)
  4. Test the transformation with UIPropertyAnimator by modifying the animator's fractionComplete in the interaction handler (LoginCritter/Sources/Login/LoginViewController.swift)

🔧Why these technologies

  • UIPropertyAnimator — Enables interactive, scrubbing animations where progress is tied directly to text input fraction (fractionComplete property), allowing fluid head rotation response
  • CATransform3D — Provides 3D perspective transformations for realistic head rotation and depth perception without requiring Metal or SceneKit
  • Vector PDF Assets — Scalable graphics that adapt to any screen size; avoids rasterized asset management and simplifies part composition
  • UITextFieldDelegate — Hooks into text field lifecycle (editing, character changes) to trigger fine-grained animation updates in real-time

⚖️Trade-offs already made

  • PDF assets with manual layout constraints instead of programmatic shape drawing

    • Why: Faster iteration and visual design fidelity; designer can work in Affinity Designer
    • Consequence: Adds dependency on asset files; any part changes require asset update and Xcode rebuild
  • Interactive animator using fractionComplete instead of duration-based keyframe animation

    • Why: Enables direct coupling between user input (text progress) and visual response, creating intuitive feedback loop
    • Consequence: More complex animation management; requires careful fraction calculation and state tracking
  • Separate view classes for each body part (LeftEye, RightEye, Mouth, etc.) instead of a single composable system

    • Why: Clear separation of concerns; each part manages its own state and animations
    • Consequence: More boilerplate and potential for inconsistency; harder to synchronize complex multi-part animations
  • No external animation libraries (e.g., Lottie) — only UIView/UIPropertyAnimator

    • Why: Reduces dependencies; full control over animation timing and interactive scrubbing
    • Consequence: All animations must be implemented manually; more code for complex choreography

🚫Non-goals (don't propose these)

  • Does not support remote/server-driven animation definitions
  • Does not persist user input or login state
  • Does not provide authentication backend integration
  • Does not support landscape orientation (portrait only, implied by login form design)
  • Not a reusable animation framework—tightly coupled to login use case

🪤Traps & gotchas

No explicit iOS deployment target or minimum version constraint visible in the file list—verify in project.pbxproj or Build Settings that you're not accidentally targeting iOS 9 when the animator API requires iOS 10+. The animation fraction calculation (textWidth / textFieldWidth) assumes text field and label widths are properly laid out; misconfigured Auto Layout or Safe Area constraints will break the head rotation. Asset PDFs must scale losslessly; rasterized PNGs in the imageset will pixelate on larger screens—verify all .imageset folders reference only .pdf files. No visible keychain or secure password storage; the 'show password' toggle is UI-only, so plain-text password display is not encrypted.

🏗️Architecture

💡Concepts to learn

  • UIPropertyAnimator Fraction-Based Control — LoginCritter's core technique—head rotation is driven by continuously updating animator.fractionComplete based on text field input, not discrete animations. Understanding this pattern is essential to modify the active state or add new continuous-response animations
  • Core Animation CABasicAnimation & CAKeyframeAnimation — Avatar part transforms (rotation, scale, opacity) are likely driven by CABasicAnimation for simple state transitions and CAKeyframeAnimation for complex multi-keyframe emotional expressions like ecstatic
  • UITextFieldDelegate Lifecycle Hooks — LoginCritter triggers state changes via textFieldDidBeginEditing, textFieldDidEndEditing, and textField(_:shouldChangeCharactersIn:) callbacks; understanding these hooks is required to add new input-driven avatar reactions
  • Vector PDF Assets in Xcassets — Avatar parts are stored as .pdf files in .imageset folders for resolution independence; this approach scales perfectly but requires understanding how Xcode rasterizes PDFs into UIImage at runtime
  • State Machine Pattern (FSM) — Avatar behavior follows a finite state machine (neutral ↔ active ↔ ecstatic, shy + peek) with allowed transitions; adding new states or fixing transition bugs requires understanding the full state graph
  • Affinity Designer Asset Pipeline — All avatar assets (login-critter.afdesign) are designed in Affinity Designer and exported as PDFs; contributors modifying avatar appearance must either learn Affinity Designer or coordinate with designers, making asset workflow non-trivial
  • Text Width / Text Field Width Ratio Animation Mapping — Head rotation fraction is calculated as textWidth / textFieldWidth; this proportional mapping is a clever non-linear animation trigger that responds to user typing speed and text length, not time
  • SnapKit/SnapKit — Auto Layout DSL commonly paired with UIKit animation projects to simplify constraint setup for multi-part avatar layout
  • Lottie-ios/lottie-ios — Alternative animation engine for iOS that uses JSON-driven After Effects exports; relevant as a comparison point for vector animation without manual UIPropertyAnimator tuning
  • realm/realm-swift — If LoginCritter evolves to persist user login state or animation preferences, Realm is the preferred local database in the Swift ecosystem
  • omaralbeik/Stores — Lightweight state management pattern for iOS that could refactor LoginCritter's state machine (neutral/active/ecstatic) into a reusable, testable store
  • jonleibowitz/JLRoutes — Deep linking framework useful if LoginCritter becomes part of a larger auth flow where different avatar states trigger different screens

🪄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.

Create AnimationController unit tests for UIPropertyAnimator fractionComplete logic

The README specifically highlights that head rotation is controlled by updating UIPropertyAnimator's fractionComplete property based on 'text width / text field width' calculation. This core animation logic lacks test coverage. A new contributor could add unit tests to verify the fraction calculation is correct across edge cases (empty text, full text field, unicode characters, etc.) and that animators respond predictably to fraction updates.

  • [ ] Create LoginCritter/Tests/ directory structure following Xcode conventions
  • [ ] Add AnimationControllerTests.swift with test cases for fractionComplete calculations
  • [ ] Test edge cases: empty UITextField, max text length, rapid text changes, animator state transitions
  • [ ] Verify animation fractions map correctly to head rotation angles
  • [ ] Add test fixtures to mock UITextField states

Add SwiftUI wrapper component for LoginCritter avatar

The project is currently UIKit-based, but the incomplete README mention ('I used Af...') suggests the documentation is unfinished. Modern iOS development heavily uses SwiftUI. Adding a SwiftUI wrapper (LoginCritterView.swift) would make this library accessible to SwiftUI projects while maintaining the existing UIKit animations. This is a high-value addition that expands the user base significantly.

  • [ ] Create LoginCritter/Sources/SwiftUI/LoginCritterView.swift wrapping the existing UIView
  • [ ] Use UIViewRepresentable protocol to bridge UIKit animation controller to SwiftUI
  • [ ] Add @State and @Binding properties to handle text input from SwiftUI TextFields
  • [ ] Create LoginCritter/Sources/SwiftUI/SwiftUIExample.swift demonstrating usage with TextField
  • [ ] Update README with SwiftUI usage example section

Extract reusable Part animation system into animatable component protocol

The file structure shows many individual body parts (Eye.imageset, Mouth-smile.imageset, Arm.imageset, etc.), each likely with custom animation logic. Currently, these appear to be handled ad-hoc. Creating a protocol-based system (AnimatablePart protocol) would allow consistent, reusable animation definitions across all parts and make it easy for contributors to add new critter expressions without duplicating animation code.

  • [ ] Create LoginCritter/Sources/Protocols/AnimatablePart.swift with required animation methods
  • [ ] Refactor existing part animations (eyes, mouth, ears, arms) to conform to protocol
  • [ ] Add PartAnimationBuilder.swift to handle composition of multi-part animations
  • [ ] Document the protocol requirements with code examples for adding new mouth expressions
  • [ ] Add test cases in PartAnimationTests.swift for protocol conformance and animation sequencing

🌿Good first issues

  • Add unit tests for the state machine logic (neutral ↔ active ↔ ecstatic transitions) to cover edge cases like rapid email/password field focus switching—currently no test files visible in the structure
  • Document the exact UIPropertyAnimator setup code (duration, timingParameters, additive behavior) in a dedicated Animations.swift file or architecture guide, since this is the core technical magic and is likely buried in a view controller
  • Create a second avatar variant (e.g., different species, art style) by adding new .imageset folders and branching the state assembly logic into a factory pattern—this will expose reusability gaps and improve the component design

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 03f2709 — Update Gems 💎 (cgoldsby)
  • 62c9da2 — Update project to Swift 5 (cgoldsby)
  • d6fe5ad — Use latest mini_magick to update app icon (cgoldsby)
  • 136fe8a — Update Gems 💎 (cgoldsby)
  • 17f856c — Merge pull request #14 from hackenbacker/master (cgoldsby)
  • 0dc2d77 — using toggle() (hackenbacker)
  • 0942d66 — improve performance (hackenbacker)
  • 2c3f92d — Update Gems 💎 (cgoldsby)
  • f2d9737 — Update to Xcode 10 and Swift 4.2 (cgoldsby)
  • 7bc952f — Merge pull request #7 from cgoldsby/PasswordPeekABoo (cgoldsby)

🔒Security observations

This iOS application (LoginCritter) demonstrates a generally secure codebase with minimal security concerns. It is a UI/animation-focused demo application with no apparent backend services, databases, network communications, or dependency vulnerabilities. The primary issues are minor configuration management concerns related to version control practices (committed Xcode user data). The application uses only local vector graphics and UI animations without any apparent injection risks, authentication mechanisms, or sensitive data handling. No hardcoded credentials, secrets, or insecure dependencies were identified in the provided file structure. Recommended improvements focus on Git hygiene rather than application security.

  • Low · Xcode User Data Committed to Repository — LoginCritter.xcodeproj/xcuserdata/. The repository contains committed Xcode user-specific data in LoginCritter.xcodeproj/xcuserdata/cgoldsby.xcuserdatad/. This directory should be added to .gitignore as it can contain sensitive developer information and build preferences that vary per developer. Fix: Add 'xcuserdata/' to .gitignore and remove the directory from version control using 'git rm -r --cached LoginCritter.xcodeproj/xcuserdata/'
  • Low · Missing or Incomplete .gitignore — .gitignore. A .gitignore file exists but the presence of committed xcuserdata suggests it may not contain comprehensive exclusions for Xcode-generated files and other sensitive build artifacts. Fix: Ensure .gitignore includes standard Xcode exclusions: '.xcuserdata/', '.xcworkspace/xcuserdata/', 'DerivedData/', 'Build/', '.DS_Store', and other Xcode-generated files

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · cgoldsby/LoginCritter — RepoPilot