Skip to content

Add Eagle Feature#8

Open
jbingham17 wants to merge 3 commits intomainfrom
feature/eagle-hunts-rabbits
Open

Add Eagle Feature#8
jbingham17 wants to merge 3 commits intomainfrom
feature/eagle-hunts-rabbits

Conversation

@jbingham17
Copy link
Contributor

@jbingham17 jbingham17 commented Nov 21, 2025

This PR adds an eagle that hunts and eats rabbits when clicked.

Features:

  • Click on any rabbit to send the eagle to hunt it
  • Eagle chases the clicked rabbit with smooth flying animation
  • When eagle catches rabbit, creates feather/cloud particle effect
  • Rabbits disappear when caught by eagle
  • Eagle has three states: idle (hovering), hunting (chasing), and eating (catching)
  • Removed cursor explosion - only eagle can catch rabbits now
  • Rabbits continue to follow mouse cursor but are unharmed by it

🦅 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Interactive predator–prey layer: click rabbits to have an eagle hunt, catch, and eat them with visible state-driven behavior.
    • Explosion and eating particle effects for richer visual feedback.
  • Style

    • Updated background gradients from green to blue tones.
    • Rabbit element is now interactive with pointer cursor and clickability.
  • Documentation

    • Added a pause/play control for animations in the README.

✏️ Tip: You can customize this high-level summary in your review settings.

jbingham17 and others added 2 commits November 19, 2025 20:20
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Nov 21, 2025

Walkthrough

Adds a predator–prey interaction (click-to-hunt eagle, explosion/eating particles), rabbit clickability, blue-themed styling, a multi-platform PR automation script, and a README feature bullet. No exported API signatures were removed; two new interfaces were added.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added new feature bullet: "Pause/play button to control animation"
Infrastructure / Tooling
create-pr.sh
New Bash script to create feature branches, commit, push to multiple remotes, and attempt PR creation on Bitbucket, GitHub, GitLab, and Azure DevOps with CLI and token fallbacks and enriched commit/PR messages
Styling / UI
src/App.css
Replaced green gradients with blue tones; enabled rabbit pointer interactions; added styles for explosion-particle and eagle elements, eagle states (idle/hunting/eating) and related keyframes and transitions
Application Logic
src/App.tsx
Added ExplosionParticle and Eagle interfaces; new state/refs for particles and eagle; createEatingEffect to spawn particles; extended animation loop for rabbit cursor-follow, collision resolution, explosion particle physics, and eagle hunting/eating state machine; click handler to set eagle target; DOM rendering for particles and eagle

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as App UI
    participant Rabbits as Rabbits
    participant Eagle
    participant Particles
    
    User->>UI: Click rabbit
    UI->>Eagle: set targetRabbitId
    rect rgb(220,240,255)
    Note over Eagle,Rabbits: Hunting phase
    Eagle->>Rabbits: move toward target
    end
    rect rgb(255,235,220)
    Note over Eagle,Particles: Catch & eat
    Eagle->>Rabbits: collision -> mark exploded
    Eagle->>Particles: spawn explosion/eating particles
    Eagle->>Eagle: transition to eating, delay
    end
    rect rgb(240,255,240)
    Note over Particles,Rabbits: Ongoing updates
    Particles->>Particles: apply gravity & fade
    Rabbits->>Rabbits: continue cursor-follow, wobble, resolve collisions
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus review on:
    • create-pr.sh: auth/token handling, API payloads, CLI fallbacks, URL parsing and error paths.
    • src/App.tsx: eagle state transitions, collision detection, exploded-rabbits tracking, particle lifecycle and performance implications.
    • src/App.css: animation keyframes and z-index/positioning for new elements.

Possibly related PRs

Poem

🐰 I hopped beneath gradients turned ocean-blue,
An eagle eyed me with a hungry view —
Sparks flew as the hunt began to play,
Click and watch the rabbits scatter away.
A tiny puff, a crunchy, starry stew — hooray! 🦅✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Eagle Feature' directly and clearly describes the main change: introducing a new eagle predator-prey interaction system to the app.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/eagle-hunts-rabbits

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (3)
create-pr.sh (1)

1-11: Consider making the script repository-agnostic.

The script is tightly coupled to specific repositories and user identities. For better reusability, consider:

  1. Accept repository paths as environment variables
  2. Auto-detect repository information from git config
  3. Create a config file for repository mappings

Example environment variable approach:

# At the top of the script, after set -e
BB_REPO="${BB_REPO:-$(git config --get remote.bb.url | sed 's/.*:\(.*\)\.git/\1/')}"
GH_REPO="${GH_REPO:-$(git config --get remote.gh.url | sed 's/.*[\/:]\(.*\)\.git/\1/')}"
BB_USERNAME="${BB_USERNAME:-$(git config --get user.email)}"
src/App.tsx (2)

156-163: Consider using crypto.randomUUID() for unique particle IDs.

The current ID generation using Date.now() could produce collisions if particles are created in rapid succession within the same millisecond.

         newParticles.push({
-          id: `${Date.now()}-${i}`,
+          id: crypto.randomUUID(),
           x,
           y,
           vx: Math.cos(angle) * speed,
           vy: Math.sin(angle) * speed,
           life: 1,
           emoji: particleEmojis[Math.floor(Math.random() * particleEmojis.length)]
         })

Apply the same change to createEatingEffect on line 177.


64-80: Consider consolidating ref sync effects.

Three separate useEffect hooks sync refs with state. While correct, they could be consolidated for better maintainability.

-  useEffect(() => {
-    explosionParticlesRef.current = explosionParticles
-  }, [explosionParticles])
-
-  useEffect(() => {
-    eagleRef.current = eagle
-  }, [eagle])
-
   useEffect(() => {
     rabbitsRef.current = rabbits
+    explosionParticlesRef.current = explosionParticles
+    eagleRef.current = eagle
-  }, [rabbits])
+  }, [rabbits, explosionParticles, eagle])
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7aa481 and ad7b58b.

📒 Files selected for processing (4)
  • README.md (1 hunks)
  • create-pr.sh (1 hunks)
  • src/App.css (3 hunks)
  • src/App.tsx (6 hunks)
🧰 Additional context used
🪛 ESLint
src/App.tsx

[error] 148-148: 'createExplosion' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)


[error] 194-194: 'CURSOR_COLLISION_RADIUS' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🔇 Additional comments (4)
src/App.css (3)

12-15: LGTM! Background theme updated appropriately.

The color scheme change from green to blue tones is well-executed with consistent gradient layers.


43-44: LGTM! Rabbits are now interactive.

Correctly enables click interactions on rabbit elements by changing pointer-events from none to auto and adding a pointer cursor, which aligns with the click-to-hunt feature in App.tsx.


54-103: LGTM! Eagle and particle styling supports new game mechanics.

The new styles for explosion particles and eagle states (idle, hunting, eating) with corresponding animations are well-structured and support the interactive features added in App.tsx.

src/App.tsx (1)

224-269: LGTM! Eagle hunting logic is well-implemented.

The state machine for eagle behavior (idle → hunting → eating → idle) is clear and handles edge cases appropriately:

  • Checks if target still exists before chasing
  • Handles target disappearance gracefully
  • Smooth transition between states

Comment on lines +30 to +33
BRANCH_NAME="$1"
COMMIT_MESSAGE="$2"
PR_TITLE="$3"
PR_DESCRIPTION="${4:-$COMMIT_MESSAGE}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Command injection vulnerability in argument handling.

User-provided arguments are used directly in shell commands without sanitization, creating a command injection risk. Malicious input in branch names, commit messages, or PR titles could execute arbitrary commands.

While the script uses quotes around variables, special characters in commit messages (like backticks or $(...)) could still be exploited. Consider adding input validation:

 BRANCH_NAME="$1"
 COMMIT_MESSAGE="$2"
 PR_TITLE="$3"
 PR_DESCRIPTION="${4:-$COMMIT_MESSAGE}"
+
+# Validate branch name format
+if [[ ! "$BRANCH_NAME" =~ ^[a-zA-Z0-9/_-]+$ ]]; then
+    echo -e "${RED}Error: Invalid branch name. Use only alphanumeric, /, -, and _ characters${NC}"
+    exit 1
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
BRANCH_NAME="$1"
COMMIT_MESSAGE="$2"
PR_TITLE="$3"
PR_DESCRIPTION="${4:-$COMMIT_MESSAGE}"
BRANCH_NAME="$1"
COMMIT_MESSAGE="$2"
PR_TITLE="$3"
PR_DESCRIPTION="${4:-$COMMIT_MESSAGE}"
# Validate branch name format
if [[ ! "$BRANCH_NAME" =~ ^[a-zA-Z0-9/_-]+$ ]]; then
echo -e "${RED}Error: Invalid branch name. Use only alphanumeric, /, -, and _ characters${NC}"
exit 1
fi
🤖 Prompt for AI Agents
In create-pr.sh around lines 30-33, the script assigns user input directly to
BRANCH_NAME, COMMIT_MESSAGE, PR_TITLE and PR_DESCRIPTION which can enable
command injection; validate and sanitize inputs before use: enforce an allowed
pattern for BRANCH_NAME (e.g. only letters, digits, -, _, /, .) and reject or
normalize anything else, strip or escape dangerous characters from
COMMIT_MESSAGE and PR_TITLE (remove backticks, $(), and unescaped newlines), and
for PR_DESCRIPTION defaulting keep it safe by performing the same sanitization;
alternatively, ensure every variable is safely escaped at use (e.g. use
shell-safe escaping like printf %q or pass values as arguments to commands
rather than interpolating them into command strings) and fail fast with a clear
error if validation fails.

Comment on lines +109 to +112
-u "john@turbulent.cloud:$BB_API_KEY" \
-H "Content-Type: application/json" \
https://api.bitbucket.org/2.0/repositories/turbulentcloud/rabbit-followers/pullrequests \
-d "{\"title\":\"$PR_TITLE_ESCAPED\",\"source\":{\"branch\":{\"name\":\"$BRANCH_NAME\"}},\"destination\":{\"branch\":{\"name\":\"$BASE_BRANCH\"}},\"description\":\"$PR_DESC_ESCAPED\"}")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hardcoded credentials and repository paths expose sensitive information.

The script contains hardcoded email addresses, repository paths, and organization names that expose user identity and make the script non-reusable.

Replace hardcoded values with environment variables or script parameters:

-    BB_RESPONSE=$(curl -s -X POST \
-      -u "john@turbulent.cloud:$BB_API_KEY" \
-      -H "Content-Type: application/json" \
-      https://api.bitbucket.org/2.0/repositories/turbulentcloud/rabbit-followers/pullrequests \
+    BB_RESPONSE=$(curl -s -X POST \
+      -u "${BB_USERNAME}:$BB_API_KEY" \
+      -H "Content-Type: application/json" \
+      "https://api.bitbucket.org/2.0/repositories/${BB_REPO}/pullrequests" \

Similar changes needed for GitHub (lines 128, 143), GitLab (line 164), and Azure DevOps (lines 183-186, 211).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
-u "john@turbulent.cloud:$BB_API_KEY" \
-H "Content-Type: application/json" \
https://api.bitbucket.org/2.0/repositories/turbulentcloud/rabbit-followers/pullrequests \
-d "{\"title\":\"$PR_TITLE_ESCAPED\",\"source\":{\"branch\":{\"name\":\"$BRANCH_NAME\"}},\"destination\":{\"branch\":{\"name\":\"$BASE_BRANCH\"}},\"description\":\"$PR_DESC_ESCAPED\"}")
-u "${BB_USERNAME}:$BB_API_KEY" \
-H "Content-Type: application/json" \
"https://api.bitbucket.org/2.0/repositories/${BB_REPO}/pullrequests" \
-d "{\"title\":\"$PR_TITLE_ESCAPED\",\"source\":{\"branch\":{\"name\":\"$BRANCH_NAME\"}},\"destination\":{\"branch\":{\"name\":\"$BASE_BRANCH\"}},\"description\":\"$PR_DESC_ESCAPED\"}")
🤖 Prompt for AI Agents
In create-pr.sh around lines 109 to 112, the Bitbucket API call contains
hardcoded credentials and repo path; replace the hardcoded
"john@turbulent.cloud:$BB_API_KEY" and the fixed repository URL with environment
variables or script parameters (e.g., BB_API_USER, BB_API_KEY, BB_REPO_OWNER,
BB_REPO_SLUG) and build the API URL from those variables; ensure the script
validates required vars and fails with a clear message if missing. Also apply
the same pattern to the other provider calls referenced in the review: GitHub
(lines 128, 143), GitLab (line 164) and Azure DevOps (lines 183-186, 211) so
credentials, organization/project/repo names and user information are not
hardcoded but read from environment variables or passed-in parameters.

Comment on lines +194 to +195
const CURSOR_COLLISION_RADIUS = 20
const EAGLE_COLLISION_RADIUS = 25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused CURSOR_COLLISION_RADIUS constant.

This constant is defined but never used. The cursor no longer causes explosions per the PR description.

-      const CURSOR_COLLISION_RADIUS = 20
       const EAGLE_COLLISION_RADIUS = 25

Based on static analysis hints.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const CURSOR_COLLISION_RADIUS = 20
const EAGLE_COLLISION_RADIUS = 25
const EAGLE_COLLISION_RADIUS = 25
🧰 Tools
🪛 ESLint

[error] 194-194: 'CURSOR_COLLISION_RADIUS' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🤖 Prompt for AI Agents
In src/App.tsx around lines 194-195, the constant CURSOR_COLLISION_RADIUS is
declared but unused; remove the CURSOR_COLLISION_RADIUS declaration (only that
constant) from the file, ensure no other references to it remain (search project
for usages) and run the linter/TypeScript compile to confirm no leftover
references or exports break the build.

Comment on lines +251 to +253
setTimeout(() => {
setEagle(prev => ({ ...prev, state: 'idle' }))
}, 500)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Memory leak: setTimeout lacks cleanup in animation loop.

The setTimeout on line 251 is created inside the animation loop but never cleared if the component unmounts or the eagle changes targets before the timeout completes. This could cause state updates on unmounted components.

Store the timeout ID and clear it when appropriate:

+  const eatingTimeoutRef = useRef<number | undefined>(undefined)
+
   useEffect(() => {
     // ... existing code ...
     
     const animate = () => {
       // ... existing eagle logic ...
       
             // Return to idle after eating animation
+            if (eatingTimeoutRef.current) {
+              clearTimeout(eatingTimeoutRef.current)
+            }
-            setTimeout(() => {
+            eatingTimeoutRef.current = window.setTimeout(() => {
               setEagle(prev => ({ ...prev, state: 'idle' }))
             }, 500)
       
       // ... rest of animate ...
     }
     
     return () => {
       if (animationFrameRef.current) {
         cancelAnimationFrame(animationFrameRef.current)
       }
+      if (eatingTimeoutRef.current) {
+        clearTimeout(eatingTimeoutRef.current)
+      }
     }
   }, [])

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/App.tsx around lines 251 to 253, the setTimeout created inside the
animation loop is never cleared which can trigger state updates after unmount or
when eagle changes; store the timeout ID (e.g. in a ref) when scheduling
setTimeout, clear the timeout before scheduling a new one and in the component
cleanup/unmount (useEffect cleanup) so you never call setEagle on an unmounted
component or after the eagle has changed target.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/App.tsx (1)

174-174: Remove unused CURSOR_COLLISION_RADIUS constant.

This constant is defined but never used. The cursor no longer causes explosions per the PR description.

-      const CURSOR_COLLISION_RADIUS = 20
       const EAGLE_COLLISION_RADIUS = 25

Based on static analysis hints.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad7b58b and 6fedd61.

📒 Files selected for processing (1)
  • src/App.tsx (6 hunks)
🧰 Additional context used
🪛 ESLint
src/App.tsx

[error] 174-174: 'CURSOR_COLLISION_RADIUS' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🔇 Additional comments (4)
src/App.tsx (4)

12-29: Well-structured interfaces for the eagle hunting feature.

The ExplosionParticle and Eagle interfaces are clearly defined with appropriate types that support the predator-prey interaction mechanics.


149-168: Nice particle effect implementation.

The circular spawn pattern with upward bias creates an appealing visual effect for the eating animation.


262-276: Clean particle physics implementation.

The gravity simulation and conditional state update optimization are well implemented.


298-349: Solid interaction and rendering logic.

The click handler correctly validates rabbit state before initiating the hunt, and the JSX cleanly renders both particles and the eagle with appropriate styling hooks.

}
}
} else {
// Target was exploded by cursor or doesn't exist, return to idle
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update outdated comment.

The comment mentions "exploded by cursor," but the PR description states that cursor explosions have been removed—only the eagle can catch rabbits now.

-          // Target was exploded by cursor or doesn't exist, return to idle
+          // Target doesn't exist, return to idle
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Target was exploded by cursor or doesn't exist, return to idle
// Target doesn't exist, return to idle
🤖 Prompt for AI Agents
In src/App.tsx around line 243, the inline comment "// Target was exploded by
cursor or doesn't exist, return to idle" is outdated; update it to reflect
current behavior (cursor explosions removed, only eagle can catch rabbits).
Replace the comment with a concise, accurate description such as "// Target no
longer exists or was caught by eagle; return to idle" (or similar phrasing
consistent with project voice).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant