Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions frontend/src/components/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Globe } from "@/components/ui/globe";
import { OrbitSatellites } from "@/components/ui/OrbitSatellites";
import { ShimmerButton } from "@/components/ui/shimmer-button";
import { Link } from "react-router-dom";
import { MouseParallax } from "./MouseParallax";

const TELEMETRY = [
{ label: "OBJECTS TRACKED", value: "34,900+" },
Expand All @@ -25,16 +26,23 @@ const fadeUp = {
export function Hero() {
return (
<section className="relative flex min-h-screen w-full items-center overflow-hidden bg-[radial-gradient(120%_90%_at_50%_10%,#0B111F_0%,#05070C_60%)] font-[Inter]">
<Particles className="absolute inset-0" quantity={220} />
<MouseParallax className="absolute inset-0" strength={20}>
<Particles quantity={220} />
</MouseParallax>
Comment on lines +29 to +31

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in VSCode Claude

(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
πŸ‘ | πŸ‘Ž



<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>
Comment on lines +39 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in VSCode Claude

(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
πŸ‘ | πŸ‘Ž


<MouseParallax strength={20} className="absolute inset-0 flex items-center justify-center">
<Globe className="h-max-[480px] w-max-[480px]" />
</div>
</MouseParallax>
Comment on lines +29 to +45

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

</div>

<div className="pointer-events-none absolute inset-0 bg-[linear-gradient(90deg,#05070C_0%,rgba(5,7,12,0.85)_38%,rgba(5,7,12,0.25)_62%,transparent_85%)] sm:bg-[linear-gradient(90deg,#05070C_0%,rgba(5,7,12,0.85)_38%,rgba(5,7,12,0.25)_62%,transparent_85%)]" />
Expand Down
59 changes: 59 additions & 0 deletions frontend/src/components/MouseParallax.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {useRef, type ReactNode} from "react";
import {motion, useMotionValue, useSpring} from "framer-motion"

interface MouseParallaxProps {
children: ReactNode;
strength?: number;
className?: string;
springConfig?: {
stiffness?: number;
damping?: number;
mass?: number;
};
}

export function MouseParallax({
children,
strength = 20,
className="",
springConfig = {stiffness: 150, damping: 15, mass: 0.1},
}: MouseParallaxProps) {
const ref = useRef<HTMLDivElement>(null);

const x = useMotionValue(0);
const y = useMotionValue(0);

const springX = useSpring(x, springConfig);
const springY = useSpring(y, springConfig);

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);
Comment on lines +29 to +40

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Suggested change
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.

};

const handleMouseLeave = () => {
x.set(0);
y.set(0);
};

return (
<motion.div
ref={ref}
className={className}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{x: springX, y: springY}}
>
{children}
</motion.div>
)
}
Loading