-
-
Notifications
You must be signed in to change notification settings - Fork 0
perf: optimize for smooth display performance #212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Major performance optimizations to achieve smooth 120Hz rendering: CRITICAL fixes: - Throttle Lenis RAF loop to 120Hz (8.33ms frame time) - Reduce backdrop-blur usage (backdrop-blur-xl → backdrop-blur-sm) - Replace GPU-expensive backdrop-blur with higher opacity backgrounds HIGH PRIORITY fixes: - Replace SVG pathLength animation with GPU-accelerated fade-in + scale - Refactor projects auto-scroll from RAF + scrollLeft to Framer Motion transforms - Remove filter: blur() animations from doc view items MEDIUM PRIORITY fixes: - Optimize navbar scroll state to prevent unnecessary re-renders - Simplify search modal loading animation (infinite repeat → CSS pulse) - Add CSS containment utilities for animated containers Performance improvements: - All animations now use GPU-accelerated properties (transform, opacity) - Eliminated layout thrashing and main thread blocking - Added contain: layout paint for animation isolation - Optimized for 120Hz displays while maintaining 60Hz compatibility https://claude.ai/code/session_68DcS
✅ Deploy Preview for eternalcodeteam-website ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Summary of ChangesHello @vLuckyyy, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a series of performance optimizations aimed at enhancing the smoothness and responsiveness of the application, particularly on high refresh rate displays. The changes include throttling requestAnimationFrame loops, reducing the use of costly CSS effects, and refactoring animations to leverage GPU acceleration. Additionally, CSS containment is employed to isolate rendering and prevent layout thrashing, resulting in a more efficient and fluid user experience. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces significant performance optimizations across the application, aligning with the goal of achieving smooth 120Hz rendering. Key improvements include throttling the Lenis RAF loop, reducing the use of GPU-expensive backdrop-blur effects, replacing pathLength SVG animations with GPU-accelerated opacity and scale transforms, and refactoring the projects auto-scroll to use Framer Motion transforms instead of a custom requestAnimationFrame loop. Additionally, unnecessary re-renders in the navbar scroll state have been optimized, and filter: blur() animations have been removed from doc view items. New CSS utilities for containment and GPU acceleration have been added to support these changes. These modifications collectively contribute to a more performant and smoother user experience.
| // Throttle RAF to 120Hz (8.33ms per frame) for optimal performance | ||
| const targetFPS = 120; | ||
| const frameTime = 1000 / targetFPS; | ||
| let lastTime = 0; | ||
|
|
||
| function raf(time: number) { | ||
| // Skip frame if not enough time has passed | ||
| if (time - lastTime < frameTime) { | ||
| requestAnimationFrame(raf); | ||
| return; | ||
| } | ||
|
|
||
| lastTime = time; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation of RAF throttling to 120Hz is a critical performance improvement. By ensuring that lenis.raf is only called when enough time has passed for a new frame at the target FPS, you prevent unnecessary work and align the animation loop with the display's refresh rate, leading to a much smoother experience, especially on high refresh rate monitors.
| initial={{ opacity: 0, scale: 0.98 }} | ||
| stroke="currentColor" | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| strokeWidth="2" | ||
| transition={{ duration: 2, ease: "easeInOut" }} | ||
| transition={{ duration: 1.5, ease: "easeOut" }} | ||
| viewport={{ once: true }} | ||
| whileInView={{ pathLength: 1 }} | ||
| whileInView={{ opacity: 1, scale: 1 }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing the SVG animation from pathLength to opacity and scale is a critical performance optimization. pathLength animations are often CPU-bound and can lead to janky rendering, whereas opacity and transform (scale) are typically GPU-accelerated properties. This refactoring ensures a much smoother and more efficient animation, directly addressing the PR's goal of GPU-accelerated animations.
| hidden: { y: 20, opacity: 0 }, | ||
| visible: { | ||
| y: 0, | ||
| opacity: 1, | ||
| filter: "blur(0px)", | ||
| transition: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing filter: blur() from the itemVariants is a significant performance win. CSS filter properties, especially blur, are known to be very expensive for the GPU and can cause considerable jank during animations. This change directly addresses the PR's goal of eliminating such performance bottlenecks.
| <div className="no-scrollbar relative flex w-full overflow-hidden contain-layout"> | ||
| <motion.div | ||
| animate={{ | ||
| x: isHovered ? undefined : [`${-singleSetWidth}px`, "0px"], | ||
| }} | ||
| className="optimize-animation flex gap-6" | ||
| initial={{ x: 0 }} | ||
| transition={{ | ||
| duration: 60, | ||
| ease: "linear", | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| }} | ||
| > | ||
| {displayProjects.map((project, index) => ( | ||
| <ProjectCard key={`${project.name}-${index}`} project={project} /> | ||
| ))} | ||
| </div> | ||
| </motion.div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Migrating the scrollable container to a motion.div with animate and transition properties, along with the optimize-animation and contain-layout classes, is a great refactoring. This leverages Framer Motion for GPU-accelerated x transforms, which is far more efficient for scrolling animations than manipulating scrollLeft. The contain properties further enhance performance by isolating the rendering of this animated element.
| <motion.div | ||
| animate={{ opacity: 1 }} | ||
| className="fixed inset-0 z-[100] flex items-start justify-center overflow-y-auto overscroll-contain bg-black/70 p-0 pt-0 backdrop-blur-md md:p-4 md:pt-[10vh] md:backdrop-blur-sm" | ||
| className="fixed inset-0 z-[100] flex items-start justify-center overflow-y-auto overscroll-contain bg-black/80 p-0 pt-0 md:p-4 md:pt-[10vh]" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| > | ||
| {/* Modal Container with Enhanced Glassmorphism */} | ||
| <div className="flex h-full flex-col overflow-hidden rounded-none border-0 bg-white/98 shadow-2xl backdrop-blur-2xl md:h-auto md:rounded-2xl md:border md:border-gray-200/60 dark:bg-gray-900/98 dark:md:border-gray-700/60"> | ||
| <div className="flex h-full flex-col overflow-hidden rounded-none border-0 bg-white shadow-2xl md:h-auto md:rounded-2xl md:border md:border-gray-200/60 dark:bg-gray-900 dark:md:border-gray-700/60"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing backdrop-blur-2xl and adjusting the background opacity (bg-white/98 to bg-white, dark:bg-gray-900/98 to dark:bg-gray-900) is a solid performance improvement. backdrop-blur can be a significant performance bottleneck, especially on lower-end devices, so this change helps ensure smoother rendering.
| scale: searchIconScale, | ||
| }} | ||
| className={isLoading ? "animate-pulse" : ""} | ||
| style={{ transformOrigin: "center" }} | ||
| transition={{ | ||
| opacity: { | ||
| duration: prefersReducedMotion ? 0 : 1.1, | ||
| repeat: isLoading ? Number.POSITIVE_INFINITY : 0, | ||
| ease: "easeInOut", | ||
| }, | ||
| scale: { duration: prefersReducedMotion ? 0 : 0.25 }, | ||
| }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replacing the Framer Motion opacity animation with className={isLoading ? "animate-pulse" : ""} for the search icon is a good optimization. CSS animations like animate-pulse are often more performant for simple effects as they can be offloaded to the GPU more effectively than JavaScript-driven animations, reducing main thread work. This aligns with the PR description's goal to simplify the search modal loading animation.
| window.requestAnimationFrame(() => { | ||
| setScrolled(window.scrollY > 20); | ||
| const isScrolled = window.scrollY > 20; | ||
| setScrolled((prev) => (prev === isScrolled ? prev : isScrolled)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimizing the setScrolled state update with setScrolled((prev) => (prev === isScrolled ? prev : isScrolled)) is a good practice. This prevents unnecessary re-renders of the Navbar component when the scroll state (whether it's scrolled past 20px or not) hasn't actually changed, improving overall component efficiency.
| scrolled || isMenuOpen | ||
| ? "border-gray-200/50 bg-white/80 backdrop-blur-xl dark:border-white/5 dark:bg-[#0a0a0a]/80" | ||
| ? "border-gray-200/50 bg-white/95 backdrop-blur-sm dark:border-white/5 dark:bg-[#0a0a0a]/95" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reduction of backdrop-blur-xl to backdrop-blur-sm and the increase in background opacity (bg-white/80 to bg-white/95, dark:bg-[#0a0a0a]/80 to dark:bg-[#0a0a0a]/95) is a positive change for performance. This directly addresses the PR's objective to reduce the impact of expensive backdrop-blur effects, leading to a smoother user interface.
| onMouseEnter={() => { | ||
| setIsHovered(true); | ||
| controls.stop(); | ||
| }} | ||
| onMouseLeave={() => { | ||
| setIsHovered(false); | ||
| controls.start({ | ||
| x: [`${-singleSetWidth}px`, "0px"], | ||
| transition: { | ||
| duration: 60, | ||
| ease: "linear", | ||
| repeat: Number.POSITIVE_INFINITY, | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The updated onMouseEnter and onMouseLeave handlers correctly integrate with Framer Motion's controls.stop() and controls.start(). This provides a clean and declarative way to manage the animation state based on user interaction, which is more robust and often more performant than manual DOM manipulation or RAF loops.

Major performance optimizations to achieve smooth 120Hz rendering:
CRITICAL fixes:
HIGH PRIORITY fixes:
MEDIUM PRIORITY fixes:
Performance improvements:
https://claude.ai/code/session_68DcS