Add reusable MouseParallax component to Hero for layered visual depth - #160
Conversation
…for enhanced visual effects
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
📝 WalkthroughWalkthroughThe PR adds a reusable ChangesHero parallax interaction
Estimated code review effort: 3 (Moderate) | ~15 minutes Possibly related issues
Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant Pointer
participant Hero
participant MouseParallax
participant BackgroundLayers
Pointer->>MouseParallax: provide pointer position
Hero->>MouseParallax: render background layer
MouseParallax->>BackgroundLayers: apply spring-smoothed translation
Pointer->>MouseParallax: trigger mouse-leave reset
MouseParallax->>BackgroundLayers: restore translation
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src/components/Hero.tsx`:
- Around line 29-45: Update the Hero component’s pointer tracking so a single
shared Hero-level region provides motion values to Particles, OrbitSatellites,
and Globe, rather than nesting separate MouseParallax handlers on overlapping
layers. Pass the shared values to each layer and apply their existing strengths
independently, ensuring all layers respond even when visually overlapped.
In `@frontend/src/components/MouseParallax.tsx`:
- Around line 29-40: Update handleMouseMove to guard against zero rect.width or
rect.height before calculating offsets; when either dimension is zero, reset
both motion values via x and y and return, preserving the existing offset
calculations for non-zero containers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a3a50a0c-cbdd-4e32-9900-c3d6e910293c
📒 Files selected for processing (2)
frontend/src/components/Hero.tsxfrontend/src/components/MouseParallax.tsx
| <MouseParallax className="absolute inset-0" strength={20}> | ||
| <Particles quantity={220} /> | ||
| </MouseParallax> | ||
|
|
||
|
|
||
| <div | ||
| className="absolute left-1/2 top-[32%] h-[240px] w-[240px] max-w-[85vw] -translate-x-1/2 -translate-y-1/2 opacity-40 | ||
| sm:left-auto sm:right-[3%] sm:top-1/2 sm:h-[380px] sm:w-[380px] sm:translate-x-0 sm:-translate-y-1/2 sm:opacity-70 | ||
| lg:right-[5%] lg:h-[520px] lg:w-[520px] lg:opacity-90" | ||
| > | ||
| <OrbitSatellites /> | ||
| <div className="absolute inset-0 flex items-center justify-center"> | ||
| <MouseParallax strength={10}> | ||
| <OrbitSatellites /> | ||
| </MouseParallax> | ||
|
|
||
| <MouseParallax strength={20} className="absolute inset-0 flex items-center justify-center"> | ||
| <Globe className="h-max-[480px] w-max-[480px]" /> | ||
| </div> | ||
| </MouseParallax> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Use one pointer-tracking region for all overlapping layers.
The absolute inset-0 globe wrapper at Line 43 covers the satellite wrapper at Lines 39-41. It receives the mouse events, so OrbitSatellites cannot update its own MouseParallax values. The particle layer has the same limitation where later hero content overlaps it.
Track the pointer on a common Hero region. Share the resulting motion values with each layer, then apply each layer strength independently.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/components/Hero.tsx` around lines 29 - 45, Update the Hero
component’s pointer tracking so a single shared Hero-level region provides
motion values to Particles, OrbitSatellites, and Globe, rather than nesting
separate MouseParallax handlers on overlapping layers. Pass the shared values to
each layer and apply their existing strengths independently, ensuring all layers
respond even when visually overlapped.
| const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => { | ||
| const rect = ref.current?.getBoundingClientRect(); | ||
| if (!rect) return; | ||
|
|
||
| const centerX = rect.left + rect.width / 2; | ||
| const centerY = rect.top + rect.height / 2; | ||
|
|
||
| const offsetX = (e.clientX - centerX) / (rect.width / 2); | ||
| const offsetY = (e.clientY - centerY) / (rect.height / 2); | ||
|
|
||
| x.set(offsetX * strength); | ||
| y.set(offsetY * strength); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Guard zero-sized containers before calculating offsets.
rect.width or rect.height can be zero when children are absolutely positioned. The division then produces Infinity or NaN, which can leave the motion values in an invalid state. Reset the values and return when either dimension is zero.
Proposed fix
const rect = ref.current?.getBoundingClientRect();
if (!rect) return;
+ if (rect.width <= 0 || rect.height <= 0) {
+ x.set(0);
+ y.set(0);
+ return;
+ }
const centerX = rect.left + rect.width / 2;📝 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.
| const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => { | |
| const rect = ref.current?.getBoundingClientRect(); | |
| if (!rect) return; | |
| const centerX = rect.left + rect.width / 2; | |
| const centerY = rect.top + rect.height / 2; | |
| const offsetX = (e.clientX - centerX) / (rect.width / 2); | |
| const offsetY = (e.clientY - centerY) / (rect.height / 2); | |
| x.set(offsetX * strength); | |
| y.set(offsetY * strength); | |
| const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => { | |
| const rect = ref.current?.getBoundingClientRect(); | |
| if (!rect) return; | |
| if (rect.width <= 0 || rect.height <= 0) { | |
| x.set(0); | |
| y.set(0); | |
| return; | |
| } | |
| const centerX = rect.left + rect.width / 2; | |
| const centerY = rect.top + rect.height / 2; | |
| const offsetX = (e.clientX - centerX) / (rect.width / 2); | |
| const offsetY = (e.clientY - centerY) / (rect.height / 2); | |
| x.set(offsetX * strength); | |
| y.set(offsetY * strength); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/components/MouseParallax.tsx` around lines 29 - 40, Update
handleMouseMove to guard against zero rect.width or rect.height before
calculating offsets; when either dimension is zero, reset both motion values via
x and y and return, preserving the existing offset calculations for non-zero
containers.
| <MouseParallax className="absolute inset-0" strength={20}> | ||
| <Particles quantity={220} /> | ||
| </MouseParallax> |
There was a problem hiding this comment.
Suggestion: The new parallax effects are unconditionally enabled, including spring-driven transforms for users whose system requests reduced motion. The existing reduced-motion handling only affects CSS animations and cannot disable these Framer Motion updates, so the hero introduces pointer-driven motion despite that accessibility preference. [possible bug]
Severity Level: Major ⚠️
- ⚠️ Landing Hero still moves under reduced-motion preference.
- ⚠️ Particle, satellite, and globe layers remain spring-driven.
- ⚠️ Accessibility behavior differs from other heroes' motion handling.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** frontend/src/components/Hero.tsx
**Line:** 29:31
**Comment:**
*Possible Bug: The new parallax effects are unconditionally enabled, including spring-driven transforms for users whose system requests reduced motion. The existing reduced-motion handling only affects CSS animations and cannot disable these Framer Motion updates, so the hero introduces pointer-driven motion despite that accessibility preference.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| <MouseParallax strength={10}> | ||
| <OrbitSatellites /> | ||
| </MouseParallax> |
There was a problem hiding this comment.
Suggestion: The satellite parallax wrapper has no sizing or positioning class, while OrbitSatellites renders only absolutely positioned content. Consequently this wrapper collapses to zero height, so it does not receive pointer movement and the parallax effect never works for the satellites; if a mouse event is delivered, the component also divides by the zero height. [layout error]
Severity Level: Major ⚠️
- ❌ Satellite layer does not receive parallax interaction.
- ⚠️ Satellite Y translation can become invalid.
- ⚠️ Hero loses the advertised layered depth effect.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** frontend/src/components/Hero.tsx
**Line:** 39:41
**Comment:**
*Layout Error: The satellite parallax wrapper has no sizing or positioning class, while `OrbitSatellites` renders only absolutely positioned content. Consequently this wrapper collapses to zero height, so it does not receive pointer movement and the parallax effect never works for the satellites; if a mouse event is delivered, the component also divides by the zero height.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
User description
Summary
MouseParallaxcomponent that tracks cursor position relative to its container and applies spring-smoothed X/Y translation via Framer Motion.strength,className, and spring physics (stiffness,damping,mass) so layers can move at different depths.strength={20}), orbit satellites (strength={10}), and globe (strength={20}) for a more immersive orbital feel.Related Issue
#152
Type of Change
Screenshots / Screen Recordings
mouse_parallax.mp4
Testing Performed
Verified that Hero layers follow the cursor with spring easing, different strengths produce distinct depth, and motion resets when the pointer leaves the parallax region.
Breaking Changes
None.
Checklist
ECSoC26 Submission
ECSoC26-L1– BeginnerECSoC26-L2– IntermediateECSoC26-L3– AdvancedCodeAnt-AI Description
Add cursor-driven layered motion to the Hero visual
What Changed
Impact
✅ More immersive Hero visuals✅ Clearer layered depth✅ Smooth reset when leaving the Hero💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.
Summary by CodeRabbit
New Features
Enhancements