Skip to content

Conversation

@nixvy-13
Copy link
Member

@nixvy-13 nixvy-13 commented Sep 5, 2025

Pues diria que lo de la lluvia está ya arreglado, pero por si acaso se me pasa algo, revisenlo.

Summary by CodeRabbit

  • New Features

    • Rain animation now dynamically adapts to device type and window size without reloading.
    • Canvas fills its container (full width and height) for responsive layouts.
    • Visuals (interaction radius, color/alpha) adjust in real time based on runtime settings and drop speed.
  • Bug Fixes

    • Improved mobile stability; touch interactions no longer interrupt the animation.
    • Smoother behavior on resize, scroll, and orientation changes with debounced updates.
  • Chores

    • No changes to the public component API.

Copilot AI review requested due to automatic review settings September 5, 2025 08:11
@coderabbitai
Copy link

coderabbitai bot commented Sep 5, 2025

Walkthrough

Refactors the rain sketch to be fully runtime- and state-driven. Replaces global/mobile flags and static arrays with React state and refs, adds SSR-safe dimension handling, debounced resize/orientation listeners, dynamic settings, and refactored helpers. P5 setup/draw now use refs and current settings; canvas resizes and drops reinitialize on dimension changes.

Changes

Cohort / File(s) Summary of changes
Runtime/state-driven P5 refactor
src/components/Rain.jsx
Removed global isMobile and static drops; added currentSettings state, dimension helpers, and multiple refs (dropsRef, p5InstanceRef, canvasRef). Implemented debounced resize/scroll/orientation handlers; SSR-safe sizing; resizeCanvas to recompute settings and reinit drops. Updated setup/draw to use refs and settings. All helpers now accept settings/dimensions. Color/alpha derived from drop.speed and settings. Container set to width/height 100%.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant React as React Component
  participant Window
  participant P5 as P5 Instance
  participant Helpers as Helpers/settings

  rect rgba(200,230,255,0.2)
    User->>React: Mount InteractiveRain
    React->>Helpers: getCurrentDimensions()
    React->>P5: setupFunction(dimensions)
    P5-->>React: p5InstanceRef, canvas created
    React->>Helpers: initializeDrops(width,height, currentSettings)
    Helpers-->>React: dropsRef seeded
  end

  loop draw loop
    P5->>React: drawFunction tick
    React->>Helpers: processDrop(drop, currentSettings, windowDimensions)
    Helpers-->>React: rendered geometry (line/curve)
    React->>P5: render with currentSettings (color/alpha/radii)
  end

  rect rgba(255,240,200,0.25)
    Window-->>React: resize/scroll/orientationchange/visibility
    React->>React: debounced via rAF
    React->>Helpers: getCurrentDimensions(), checkIfMobile()
    React->>React: update currentSettings
    React->>P5: resizeCanvas(new dimensions)
    React->>Helpers: initializeDrops(new width/height, currentSettings)
    Helpers-->>React: dropsRef replaced
  end

  note over React,P5: Refs (dropsRef, p5InstanceRef, canvasRef) persist across renders
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I tap my paws on canvas wide,
Raindrops dance and settings glide—
Refs burrow deep, state keeps the beat,
Winds adjust with mobile feet.
Resize skies, redraw delight,
A nimble storm in polished light.
Hop-hop—the code feels right! 🌧️🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/lluvia

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@cloudflare-workers-and-pages
Copy link
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
yellowumbrella-web c4361c4 Commit Preview URL

Branch Preview URL
Sep 05 2025, 08:11 AM

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the Rain component to improve mobile responsiveness and dynamic behavior. The changes focus on making the rain animation more adaptive to different screen sizes and device orientations while adding proper cleanup and performance optimizations.

  • Converts static mobile detection to dynamic state-based detection with proper event handling
  • Implements comprehensive window resize, scroll, and orientation change handling
  • Adds proper cleanup and performance optimizations with refs and debouncing

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.


return {
width: window.innerWidth,
height: Math.max(window.innerHeight, document.documentElement.scrollHeight, document.body.scrollHeight)
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

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

This calculation on every resize/scroll event can be expensive. Consider caching these DOM measurements or using a more efficient approach like ResizeObserver for better performance.

Copilot uses AI. Check for mistakes.
Comment on lines +147 to +149
if (mobile) {
document.addEventListener('touchstart', handleTouchStart, { passive: false });
}
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

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

The mobile variable is captured in the effect's closure and won't update if the device orientation changes. This could lead to inconsistent touch event handling. Use isMobile state instead.

Copilot uses AI. Check for mistakes.
Comment on lines +163 to +165
if (mobile) {
document.removeEventListener('touchstart', handleTouchStart);
}
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

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

Same issue as the addEventListener - using the stale mobile variable from closure instead of current state. This could prevent proper cleanup of touch event listeners.

Suggested change
if (mobile) {
document.removeEventListener('touchstart', handleTouchStart);
}
if (checkIfMobile()) {
document.removeEventListener('touchstart', handleTouchStart);
}

Copilot uses AI. Check for mistakes.

clearTimeout(initialTimeout);
};
}, [resizeCanvas, checkIfMobile, updateSettings, windowDimensions.height, getCurrentDimensions]);
Copy link

Copilot AI Sep 5, 2025

Choose a reason for hiding this comment

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

Including windowDimensions.height in the dependency array will cause the entire effect to re-run every time the height changes, potentially creating duplicate event listeners. Consider removing it since resize events already handle dimension changes.

Suggested change
}, [resizeCanvas, checkIfMobile, updateSettings, windowDimensions.height, getCurrentDimensions]);
}, [resizeCanvas, checkIfMobile, updateSettings, getCurrentDimensions]);

Copilot uses AI. Check for mistakes.
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

Caution

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

⚠️ Outside diff range comments (1)
src/components/Rain.jsx (1)

4-24: Define mouseInteractionRadius at init to avoid NaNs during first frames

currentSettings starts without mouseInteractionRadius; draw/processDrop may run before updateSettings executes, leading to NaN comparisons/sqrt and broken rendering. Seed a default in SETTINGS.

 const SETTINGS = {
   dropNumber: 200,
   dropLength: 30,
   globalSpeedMultiplier: 5,
   interactionStepDivider: 10,
   useUmbrella: false,
   mouseUmbrellaShadow: 0.8,
   windSpeed: -10,
+  // Default to non-mobile; updateSettings will override at runtime
+  mouseInteractionRadius: 100,
   dropColor: {
     r: 220,
     g: 220,
     b: 255,
     baseAlpha: 32
   }
 }

Also applies to: 47-52, 256-276, 268-276, 300-301

🧹 Nitpick comments (6)
src/components/Rain.jsx (6)

39-45: Mobile detection: prefer matchMedia/pointer coarse; decouple from magic 800px

window.matchMedia('(pointer: coarse)') or CSS breakpoints via matchMedia are more robust than a fixed width.

-const checkIfMobile = useCallback(() => {
-  const mobile = typeof window !== 'undefined' && window.innerWidth <= 800;
+const checkIfMobile = useCallback(() => {
+  const mobile =
+    typeof window !== 'undefined' &&
+    (window.matchMedia?.('(pointer: coarse)').matches || window.innerWidth <= 800);
   setIsMobile(mobile);
   return mobile;
 }, []);

194-196: Avoid double clear per frame

p5.clear() already clears; background(0, 0) right after is redundant.

- p5.clear();
- p5.background(0, 0);
+ p5.clear();

65-77: Off-by-one on initial seeding (x/y can equal width/height)

Math.round(Math.random() * width) can return width; use floor to keep coordinates within [0, width-1].

- x: Math.round(Math.random() * width),
- y: Math.round(Math.random() * height),
+ x: Math.floor(Math.random() * width),
+ y: Math.floor(Math.random() * height),

Also applies to: 69-71


287-291: Promote magic constant 20 to a setting for easier tuning

Expose as settings.xSmoothingThreshold and use it here.

- if (xDiff > 20) {
+ if (xDiff > settings.xSmoothingThreshold) {
     // Handle large x difference
     calculatedX = lastX;
   }

Add to SETTINGS:

 windSpeed: -10,
+xSmoothingThreshold: 20,
 dropColor: { ... }

367-369: Remove unused _frictionOffset

Dead code adds maintenance noise.

-const _frictionOffset = (x, distanceFromOrigin, settings) => {
-  return Math.round(Math.cos(x + distanceFromOrigin) * settings.windSpeed);
-}

31-33: Use isMobile state for binding lifecycle or drop it

isMobile is set but not used to (un)bind listeners post-resize. Either bind/unbind based on isMobile (see earlier snippet) or remove the state to reduce complexity.

Also applies to: 146-149, 163-165

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 991c0db and c4361c4.

📒 Files selected for processing (1)
  • src/components/Rain.jsx (8 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Workers Builds: yellowumbrella-web
🔇 Additional comments (1)
src/components/Rain.jsx (1)

223-235: Verify pointer data reliability with z-index: -1

With the canvas behind content, p5 may not receive mouse/touch events; umbrella interaction can be inert under overlays. Please validate on pages with overlaying elements.

Comment on lines +55 to +62
const getCurrentDimensions = useCallback(() => {
if (typeof window === 'undefined') return { width: 800, height: 600 };

return {
width: window.innerWidth,
height: Math.max(window.innerHeight, document.documentElement.scrollHeight, document.body.scrollHeight)
};
}, []);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid sizing canvas to document scrollHeight (huge offscreen surfaces, jank)

Using Math.max(...scrollHeight) can make the canvas as tall as the whole page; every frame clears/strokes that area. Prefer viewport height and drop the scroll-based resize.

 const getCurrentDimensions = useCallback(() => {
   if (typeof window === 'undefined') return { width: 800, height: 600 };
-  return {
-      width: window.innerWidth,
-      height: Math.max(window.innerHeight, document.documentElement.scrollHeight, document.body.scrollHeight)
-  };
+  return { width: window.innerWidth, height: window.innerHeight };
 }, []);
 
-        const handleScroll = () => {
-          // Actualizar dimensiones en scroll para manejar páginas largas
-          if (animationRef.current) {
-            cancelAnimationFrame(animationRef.current);
-          }
-          animationRef.current = requestAnimationFrame(() => {
-            const newDimensions = getCurrentDimensions();
-            if (newDimensions.height !== windowDimensions.height && p5InstanceRef.current) {
-              p5InstanceRef.current.resizeCanvas(newDimensions.width, newDimensions.height);
-              setWindowDimensions(newDimensions);
-            }
-          });
-        };
-
 // Agregar event listeners
 window.addEventListener('resize', handleResize, { passive: true });
-window.addEventListener('scroll', handleScroll, { passive: true });
 window.addEventListener('orientationchange', handleResize, { passive: true });
 ...
 // Cleanup
 window.removeEventListener('resize', handleResize);
-window.removeEventListener('scroll', handleScroll);
 window.removeEventListener('orientationchange', handleResize);

Also applies to: 113-126, 142-142, 159-159

🤖 Prompt for AI Agents
In src/components/Rain.jsx around lines 55-62 (and also apply same fix at
113-126, 142, 159), the canvas sizing uses Math.max(window.innerHeight,
document.documentElement.scrollHeight, document.body.scrollHeight) which can
expand the canvas to the full document scrollHeight causing huge offscreen
surfaces and jank; replace that logic to use only the viewport height
(window.innerHeight) with an SSR-safe fallback (e.g., return {width: 800,
height: 600} when window is undefined), remove any use of document.*scrollHeight
in resize/dimension calculations, and ensure all other occurrences referenced
(lines 113-126, 142, 159) are changed the same way so the canvas is sized to the
viewport only.

Comment on lines +135 to +139
const handleTouchStart = (e) => {
// Prevenir que los toques detengan la animación
e.preventDefault();
};

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Document-level touchstart preventDefault blocks page scroll/gestures on mobile

Preventing default at the document level disables scrolling. Scope it to the canvas only.

-// Prevenir que los toques interfieran con la animación
-if (mobile) {
-  document.addEventListener('touchstart', handleTouchStart, { passive: false });
-}
+// Limitar a solo el canvas para no bloquear el scroll de la página
+if (mobile && canvasRef.current?.elt) {
+  canvasRef.current.elt.addEventListener('touchstart', handleTouchStart, { passive: false });
+}
 ...
-if (mobile) {
-  document.removeEventListener('touchstart', handleTouchStart);
-}
+if (canvasRef.current?.elt) {
+  canvasRef.current.elt.removeEventListener('touchstart', handleTouchStart);
+}

Optionally, add a small effect to (un)bind when isMobile or the canvas becomes available:

useEffect(() => {
  const el = canvasRef.current?.elt;
  if (!el) return;
  if (isMobile) {
    el.addEventListener('touchstart', handleTouchStart, { passive: false });
    return () => el.removeEventListener('touchstart', handleTouchStart);
  }
}, [isMobile]);

Also applies to: 146-149, 163-165

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.

2 participants