Skip to content

Conversation

@kuNA78-hub
Copy link

@kuNA78-hub kuNA78-hub commented Oct 13, 2025

Description

This pull request introduces a suite of dynamic, theme-aware animations to the Hacktoberfest 2025 landing page. The goal is to create a more festive, engaging, and immersive experience for visitors and contributors during the event.

Key Enhancements

🎃 Falling Particles: A lightweight HTML5 canvas animation adds falling pumpkins and autumn leaves that gently drift across the screen.

🎉 Confetti Bursts: Celebratory confetti periodically bursts from the countdown timer, enhancing the festive atmosphere.

✨ Pulsing Glow Effect: The countdown timer now features a subtle, pulsing glow effect using Framer Motion to draw attention and build excitement.

🎨 Interactive Mouse Trail: A light trail follows the user's cursor, adding a fun, interactive element.

♿ Accessibility: All animations fully respect the prefers-reduced-motion browser setting to ensure a comfortable experience for all users.

🚀 Optimized Performance: All effects are rendered in a single, unified requestAnimationFrame loop on a single canvas to ensure smooth performance (stable <60 FPS) and low resource usage.

🌓 Full Theme Support: All text and animation effects automatically adapt to both light and dark modes for perfect visibility and contrast.

Video Demonstration

updated.mp4

Summary by CodeRabbit

  • New Features
    • Revamped Hacktoberfest 2025 landing with updated visuals, background effects, and action links; event shown as active.
    • New festive visuals: particle background with interactive hover trails, canvas-based animations (pumpkins, confetti, mouse trails), and 3D falling leaves.
    • New subtle pulse-glow UI animation utility.
  • Accessibility
    • All motion and visual effects respect users’ reduced-motion preference and disable accordingly.
  • Chores
    • Build tooling and type/dependency updates.

@coderabbitai
Copy link

coderabbitai bot commented Oct 13, 2025

Walkthrough

Adds multiple festive visual effect components (canvas particles, tsparticles background, 3D falling leaves and leaf mesh), a Hacktoberfest client wrapper, a prefers-reduced-motion hook, a CSS pulse-glow utility, and updates deps/TS config and scripts.

Changes

Cohort / File(s) Summary
Styling: Pulse Glow
app/globals.css
Adds @keyframes pulse-glow and .animate-pulse-glow utility for a looping glow/scale animation.
Hacktoberfest Page Wrapper
app/hacktoberfest/page.tsx
Replaces inline UI with a wrapper that renders HacktoberfestClientContent (active true, eventYear 2025) and surrounding background markup.
Hacktoberfest Client UI
components/hacktoberfest-client-content.tsx
New client component that renders header, badges, conditional messaging, countdown, action links, and orchestrates canvas visual effects with init/intervals and cleanup.
Effects: 3D Leaves & Leaf Entity
components/effects/falling-leaves-3d.tsx, components/effects/leaf-3d.tsx
Adds FallingLeaves3D (React client component using @react-three/fiber) and Leaf3D mesh with per-frame gravity/wind/rotation, boundary reset, randomized color/scale, and reduced-motion gating.
Effects: tsparticles Background
components/effects/festive-background.tsx
Adds FestiveBackground that initializes tsparticles engine and renders Particles with options that respect reduced-motion.
Effects: Canvas Animation
components/effects/festive-canvas-animation.tsx
Adds FestiveCanvasAnimation: canvas-driven pumpkins/leaves/confetti, trails, responsive DPR resizing, mouse interactions, animation loop, and reduced-motion gating.
Accessibility Hook
hooks/use-prefers-reduced-motion.ts
Adds usePrefersReducedMotion hook to observe (prefers-reduced-motion: reduce) and return boolean preference with listener cleanup.
Tooling & Deps
package.json, tsconfig.json
Adds scripts/typechecking, introduces @react-three/fiber, @react-three/drei, react-tsparticles, tsparticles-slim, and updates TypeScript types and types config in tsconfig.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Page as /app/hacktoberfest/page.tsx
  participant Client as HacktoberfestClientContent
  participant RM as usePrefersReducedMotion
  participant Effects as FestiveCanvasAnimation / FestiveBackground / FallingLeaves3D
  participant Countdown as CleanCountdown

  User->>Page: Request /hacktoberfest
  Page->>Client: Render(active: true, eventYear: 2025, hacktoberfestEnd)
  Client->>RM: Query reduced-motion
  alt reduced-motion = true
    Client-->>Effects: Skip visual effects (no mount)
  else
    Client->>Effects: Initialize canvases, particles, 3D scene, listeners
  end
  alt active = true
    Client->>Countdown: Render countdown
  else
    Client-->>User: Render "Coming soon" message
  end
  Note over Effects: Effects run loops, spawn particles/leaves, attach mouse handlers\nand register cleanup on unmount
Loading
sequenceDiagram
  autonumber
  participant FL as FallingLeaves3D
  participant RM as usePrefersReducedMotion
  participant Canvas as @react-three/fiber Canvas
  participant Leaf as Leaf3D (x N)

  FL->>RM: Check preference
  alt reduced-motion = true
    FL-->>FL: return null (do not render)
  else
    FL->>Canvas: Mount scene (lights, env)
    Canvas->>Leaf: Instantiate N leaves (viewport-aware)
    loop each frame
      Leaf->>Leaf: Apply gravity, wind, rotation
      alt y < ground
        Leaf->>Leaf: Reset position/rotation/scale/color
      end
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Poem

I hop through code with autumn cheer,
Leaves and pumpkins sparkle near,
Trails that follow every twitch and nod,
I plant these bits beneath the sod.
Deploy the joy — a rabbit's prod! 🐇🍁🎃

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The description provides a clear overview of the animations and includes a video demonstration, but it omits several required sections from the repository’s PR template such as the pre-submission checklist, type of changes selection, testing completed, development setup verification, code quality checklist, related issues, and additional notes, making it incomplete against the prescribed structure. Please update the PR description to follow the repository template by adding the pre-submission checklist, selecting the appropriate type of changes, filling out testing completed and development setup verification sections, including code quality checks, linking related issues, and providing any additional notes as specified.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title clearly describes the main change by stating that festive animations are being added to the Hacktoberfest page, using concise and specific language that aligns with the feature additions in the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ddb1398 and 874061d.

📒 Files selected for processing (1)
  • components/effects/falling-leaves-3d.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
components/effects/falling-leaves-3d.tsx (2)
hooks/use-prefers-reduced-motion.ts (1)
  • usePrefersReducedMotion (5-23)
components/effects/leaf-3d.tsx (1)
  • Leaf3D (26-87)
🔇 Additional comments (1)
components/effects/falling-leaves-3d.tsx (1)

40-69: Clean 3D rendering implementation.

The Canvas configuration and component structure look good. Performance settings (dpr, antialias, power preference) are appropriate for this use case, and the Suspense wrapper properly handles async loading of the 3D scene.


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.

❤️ Share

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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
package.json (1)

25-27: tsparticles packages are mixed across major versions (v2 and v3) — unify or it will break

Code imports v3 engine (@tsparticles/engine) but also uses v2 packages (react-tsparticles, tsparticles-slim). This will cause type/runtime mismatches. Standardize on v3 across code and deps.

Apply this diff to move fully to v3:

   "dependencies": {
@@
-    "@tsparticles/react": "^3.0.0",
-    "@tsparticles/slim": "^3.9.1",
+    "@tsparticles/react": "^3.9.1",
+    "@tsparticles/slim": "^3.9.1",
@@
-    "react-tsparticles": "^2.12.2",
@@
-    "tsparticles-slim": "^2.12.0",

Then update imports in code to use @tsparticles/react and @tsparticles/slim (see festive-background.tsx comment).

Also applies to: 46-46, 51-51

🧹 Nitpick comments (10)
hooks/use-prefers-reduced-motion.ts (1)

8-20: Hook looks good; consider legacy listener fallback only if you target very old browsers

Implementation is correct for modern browsers. If you need legacy Safari support, add addListener/removeListener fallback.

Example fallback:

-    mediaQuery.addEventListener("change", listener);
-    return () => mediaQuery.removeEventListener("change", listener);
+    if (mediaQuery.addEventListener) {
+      mediaQuery.addEventListener("change", listener);
+      return () => mediaQuery.removeEventListener?.("change", listener);
+    } else {
+      // @ts-expect-error legacy
+      mediaQuery.addListener(listener);
+      // @ts-expect-error legacy
+      return () => mediaQuery.removeListener(listener);
+    }
components/effects/festive-canvas-animation.tsx (3)

217-220: Spawn particles using the canvas width, not window width

Using window.innerWidth can misplace particles if the canvas isn’t full-viewport. Use rect.width from the measured canvas.

-      const particleCount = window.innerWidth < 768 ? 20 : 40;
-      particlesRef.current = Array.from({ length: particleCount }, () => new Particle(window.innerWidth));
+      const particleCount = rect.width < 768 ? 20 : 40;
+      particlesRef.current = Array.from({ length: particleCount }, () => new Particle(rect.width));

155-166: Optional: clear the scaled canvas using CSS pixel units

Since the context is scaled by DPR, clearing with canvas.width/height operates in device pixels and is larger than necessary. Use CSS pixel dimensions to avoid extra work.

-    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    const dpr = window.devicePixelRatio || 1;
+    ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr);

Also applies to: 168-176


178-199: DRY: Prefer the shared hook for reduced motion

You already have usePrefersReducedMotion. Consider using it here instead of duplicating matchMedia logic.

components/effects/festive-background.tsx (1)

9-20: Consider reusing existing components/ui/particles.tsx

There’s already a Particles wrapper that initializes the engine and merges options. Reusing it avoids duplicate init logic and keeps styling consistent.

Based on learnings; see components/ui/particles.tsx snippet.

Also applies to: 26-98, 100-112

app/globals.css (1)

352-367: Respect reduced motion and hint compositing for the glow animation

Add a motion-reduced override and will-change to avoid unnecessary work for users who prefer reduced motion.

 @keyframes pulse-glow {
   0%, 100% {
     box-shadow: 0 0 20px 0px rgba(255, 165, 0, 0.2);
     transform: scale(1);
   }
   50% {
     box-shadow: 0 0 40px 10px rgba(255, 165, 0, 0.4);
     transform: scale(1.02);
   }
 }
 
 .animate-pulse-glow {
   border-radius: 9999px; /* Ensures the glow effect is rounded */
   transition: box-shadow 0.5s ease-in-out, transform 0.5s ease-in-out;
   animation: pulse-glow 4s infinite ease-in-out;
+  will-change: transform, box-shadow;
 }
+
+@media (prefers-reduced-motion: reduce) {
+  .animate-pulse-glow {
+    animation: none;
+    transition: none;
+  }
+}
app/hacktoberfest/page.tsx (1)

4-8: Confirm forcing active=true (and consider timezone-safe date parsing)

If this is for demo only, fine; otherwise compute active from start/end. Also consider appending “Z” to the ISO strings to avoid locale-dependent parsing.

- const eventYear = 2025;
+ const eventYear = 2025;
  const start = new Date(`${eventYear}-10-01T00:00:00`);
  const end = new Date(`${eventYear}-10-31T23:59:59`);
- const active = true;
+ const now = new Date();
+ const active = now >= start && now <= end;

Timezone-safe variant:

- const start = new Date(`${eventYear}-10-01T00:00:00`);
- const end = new Date(`${eventYear}-10-31T23:59:59`);
+ const start = new Date(`${eventYear}-10-01T00:00:00Z`);
+ const end = new Date(`${eventYear}-10-31T23:59:59Z`);
components/effects/falling-leaves-3d.tsx (1)

38-46: Optional: cap device pixel ratio to reduce GPU load

Clamping DPR can significantly reduce fill rate on high‑DPI screens.

-      <Canvas
+      <Canvas
         camera={{ position: [0, 0, 15], fov: 75 }}
         style={{ background: 'transparent' }}
-        gl={{ antialias: true }}
+        dpr={[1, 2]}
+        gl={{ antialias: true, powerPreference: "high-performance" }}
       >
components/hacktoberfest-client-content.tsx (2)

22-38: Remove unused glowControls (dead code) or wire it up

useAnimation() is started but never bound to a motion component; .stop() is called on cleanup only. Either bind animate={glowControls} to the target element or remove this code.

-import { motion, useAnimation } from "framer-motion";
+import { motion } from "framer-motion";
@@
-  const glowControls = useAnimation();
@@
-    // Gradient glow animation
-    const animateGlow = async () => {
-      await glowControls.start({
-        opacity: [0.2, 0.5, 0.2],
-        scale: [1, 1.1, 1],
-        transition: { duration: 2, repeat: Infinity, ease: "easeInOut" },
-      });
-    };
-    animateGlow();
@@
-      glowControls.stop();

If you prefer keeping it, attach it:

-        <motion.div
+        <motion.div
           className="mb-16 flex justify-center relative"
-          animate={{
+          animate={{
             boxShadow: [
               "0 0 20px rgba(255, 165, 0, 0.3)",
               "0 0 40px rgba(255, 165, 0, 0.6)",
               "0 0 20px rgba(255, 165, 0, 0.3)",
             ],
             transition: { duration: 2, repeat: Infinity, ease: "easeInOut" },
           }}
         >

Also applies to: 214-215


96-102: Consider a single rAF render loop for all effects

Running three independent loops on the same canvas can cause overdraw/flicker and extra work. Merging updates (particles, confetti, trail) into one loop improves stability and aligns with your PR goal.

Also applies to: 149-158, 198-208

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55ecc95 and f3b78e6.

📒 Files selected for processing (10)
  • app/globals.css (1 hunks)
  • app/hacktoberfest/page.tsx (1 hunks)
  • components/effects/falling-leaves-3d.tsx (1 hunks)
  • components/effects/festive-background.tsx (1 hunks)
  • components/effects/festive-canvas-animation.tsx (1 hunks)
  • components/effects/leaf-3d.tsx (1 hunks)
  • components/hacktoberfest-client-content.tsx (1 hunks)
  • hooks/use-prefers-reduced-motion.ts (1 hunks)
  • package.json (3 hunks)
  • tsconfig.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
app/hacktoberfest/page.tsx (1)
components/hacktoberfest-client-content.tsx (1)
  • HacktoberfestClientContent (17-326)
components/hacktoberfest-client-content.tsx (3)
components/ui/aurora-text.tsx (1)
  • AuroraText (12-41)
components/utils/clean-countdown.tsx (1)
  • CleanCountdown (24-146)
components/utils/icons.tsx (1)
  • Icons (4-199)
components/effects/falling-leaves-3d.tsx (2)
hooks/use-prefers-reduced-motion.ts (1)
  • usePrefersReducedMotion (5-23)
components/effects/leaf-3d.tsx (1)
  • Leaf3D (25-84)
components/effects/festive-background.tsx (2)
hooks/use-prefers-reduced-motion.ts (1)
  • usePrefersReducedMotion (5-23)
components/ui/particles.tsx (1)
  • Particles (125-249)
🪛 Biome (2.1.2)
components/effects/falling-leaves-3d.tsx

[error] 21-21: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🔇 Additional comments (2)
components/effects/festive-background.tsx (1)

26-98: Options respect reduced motion — looks good

Config disables movement and reduces count when reduced motion is on. Nice.

Confirm that the “trail” interactivity is also disabled when prefersReducedMotion is true (it is, via onHover.enable). Good.

package.json (1)

22-24: three@^0.180.0 satisfies @react-three/fiber and @react-three/drei peer requirements three@^0.180.0 meets the ≥0.156 (fiber) and ≥0.159 (drei) constraints.

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: 2

🧹 Nitpick comments (1)
components/effects/leaf-3d.tsx (1)

26-30: Add cleanup to dispose geometry and material on unmount.

Three.js geometries and materials must be explicitly disposed to prevent GPU memory leaks. Currently, the memoized material and geometry are never disposed when the component unmounts.

Add a cleanup effect after the memoized values:

  const geometry = useMemo(() => {
    const shape = new Shape();
    const width = 0.5 + Math.random() * 0.3;
    const height = 0.7 + Math.random() * 0.4;

    shape.moveTo(0, height / 2);
    shape.bezierCurveTo(width / 2, height / 2 * 0.8, width / 2, -height / 2 * 0.8, 0, -height / 2);
    shape.bezierCurveTo(-width / 2, -height / 2 * 0.8, -width / 2, height / 2 * 0.8, 0, height / 2);

    return new ShapeGeometry(shape);
  }, []);

  // Add cleanup effect
  React.useEffect(() => {
    return () => {
      geometry.dispose();
      material.dispose();
    };
  }, [geometry, material]);

Also applies to: 32-43

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3b78e6 and ddb1398.

📒 Files selected for processing (1)
  • components/effects/leaf-3d.tsx (1 hunks)
🔇 Additional comments (1)
components/effects/leaf-3d.tsx (1)

3-4: Previous import and memory leak issues are now resolved.

The imports of Three.js classes (Shape, ShapeGeometry, Mesh) are now correct, and the material color is properly updated in place during reset instead of creating new material instances. These fixes address the critical issues from the previous review.

Also applies to: 28-28, 34-34, 42-42, 72-73

@SaiKarthikeya-234 SaiKarthikeya-234 changed the base branch from main to develop October 13, 2025 12:36
@SaiKarthikeya-234
Copy link
Contributor

@wizaye review this

@wizaye
Copy link
Contributor

wizaye commented Oct 13, 2025

@kuNA78-hub Good work, but it needs some improvement can you do that?

@kuNA78-hub
Copy link
Author

@kuNA78-hub Good work, but it needs some improvement can you do that?

@wizaye Thanks for the review! I'm happy to make the improvements. Could you please provide some specific details on what needs to be changed?

@wizaye
Copy link
Contributor

wizaye commented Oct 14, 2025

@kuNA78-hub Good work, but it needs some improvement can you do that?

@wizaye Thanks for the review! I'm happy to make the improvements. Could you please provide some specific details on what needs to be changed?
just add subtle animations not the flashy ones and also do not change the look of the original page

@kuNA78-hub
Copy link
Author

@kuNA78-hub Good work, but it needs some improvement can you do that?

@wizaye Thanks for the review! I'm happy to make the improvements. Could you please provide some specific details on what needs to be changed?
just add subtle animations not the flashy ones and also do not change the look of the original page

@kuNA78-hub Good work, but it needs some improvement can you do that?

@wizaye Thanks for the review! I'm happy to make the improvements. Could you please provide some specific details on what needs to be changed?
just add subtle animations not the flashy ones and also do not change the look of the original page

Sure.
I'll add that now.

@kuNA78-hub
Copy link
Author

trailer.mp4

@wizaye Thanks for the feedback! I've toned down the animations to be more subtle while keeping the original design intact.

Before I proceed further, could you take a look and confirm if this direction works?

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.

4 participants