Skip to content

⚡ Bolt: Optimize BackgroundCarousel rendering#57

Open
anyulled wants to merge 2 commits intomainfrom
bolt-optimize-background-carousel-7937693282089218174
Open

⚡ Bolt: Optimize BackgroundCarousel rendering#57
anyulled wants to merge 2 commits intomainfrom
bolt-optimize-background-carousel-7937693282089218174

Conversation

@anyulled
Copy link
Owner

@anyulled anyulled commented Feb 23, 2026

💡 What: Optimized BackgroundCarousel to only render Next/Image components for the current, previous, and next slides, instead of rendering all 15 images at once. Also scoped the CSS ken-burns animation to only run on active/visible slides.

🎯 Why: The carousel was rendering 15 large hero images on page load, even though only one is visible. This caused unnecessary network requests, memory usage, and DOM node creation. The CSS animation was also running on hidden slides.

📊 Impact:

  • Reduces initial image DOM nodes from 15 to 3 (~80% reduction).
  • Reduces initial network requests for images (lazy loading handles the rest, but this ensures they aren't even in the DOM).
  • Saves CPU/GPU by not animating hidden elements.

🔬 Measurement:

  • Verified using a Playwright script that counts the number of img tags in the carousel. The count dropped from ~15 to 3.
  • Verified npm test output shows significantly fewer "unconfigured quality" warnings (proxy for image rendering count).

PR created automatically by Jules for task 7937693282089218174 started by @anyulled

Summary by CodeRabbit

  • Refactor

    • Carousel now renders only the active and adjacent slides to reduce rendering load and improve runtime performance.
  • Style

    • Ken‑burns animation refined to start at correct scale and apply only to active/adjacent slides for smoother visuals.
  • Tests

    • Homepage edition test updated to target a specific header element and assert at least two occurrences.

- Conditionally render Next/Image components in BackgroundCarousel based on active index (render only active, next, prev).
- Scope `ken-burns` CSS animation to active/prev slides to prevent premature execution on preloaded slides.
- Reduces initial DOM node count and image loading from ~15 to 3.

References: #perf-opt

Co-authored-by: anyulled <100741+anyulled@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel
Copy link

vercel bot commented Feb 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devbcn Ready Ready Preview, Comment Feb 23, 2026 9:34am

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @anyulled, 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 significant performance enhancements to the BackgroundCarousel component. By intelligently controlling the rendering of Next/Image components and the application of CSS animations, it drastically reduces the initial load on the browser. This optimization minimizes DOM complexity, decreases network requests for images, and conserves processing power by only animating visible elements, leading to a smoother and more efficient user experience.

Highlights

  • Image Rendering Optimization: Optimized the BackgroundCarousel component to render only the current, previous, and next Next/Image components, significantly reducing initial DOM nodes and network requests from 15 to 3.
  • CSS Animation Scoping: Scoped the ken-burns CSS animation to apply exclusively to active or visible carousel slides, preventing unnecessary CPU/GPU usage on hidden elements.
Changelog
  • components/BackgroundCarousel.tsx
    • Introduced activeIndex state to track the currently visible slide.
    • Implemented shouldRenderSlide logic to conditionally render only the active, previous, and next image slides.
    • Integrated onSlideChange event handler with the Swiper component to update the activeIndex.
    • Modified the image rendering loop to use the shouldRenderSlide function, effectively limiting the number of rendered Next/Image components.
  • styles/components/_background-carousel.scss
    • Refined the ken-burns animation application to target only .swiper-slide-active, .swiper-slide-duplicate-active, and .swiper-slide-prev elements.
    • Added a base transform: scale(1) to the .ken-burns class.
Activity
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

BackgroundCarousel now tracks the active slide and conditionally renders only the active, previous, and next slides; ken-burns animation and related styles are applied only when slide content is actually rendered. A Cypress selector in the home editions test was tightened.

Changes

Cohort / File(s) Summary
Carousel Rendering
components/BackgroundCarousel.tsx
Added activeIndex state updated from Swiper's onSlideChange; introduced shouldRenderSlide(index) to render only active/prev/next slide content and avoid rendering others; preserved prefers-reduced-motion/ken-burns behavior but scoped to rendered slides.
Styles: ken-burns gating
styles/components/_background-carousel.scss
Set transform: scale(1) for ken-burns slides and added selector grouping so the kenBurns animation applies only to active/duplicate-active/prev slides, preventing animation on non-visible slides.
Test selector update
cypress/e2e/home/home-editions.cy.ts
Changed selector inside .hero8-header from all h5 elements to .hero8-header__event-line and updated assertion to expect at least 2 matches.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hop along the carousel’s rim,
Three slides dance where once were grim.
Ken-burns waits for its cue to play,
Tests now seek the event-line sway.
Efficiency nibbles, bright and slim.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main optimization: reducing BackgroundCarousel rendering to only active/adjacent slides, which is the primary change across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bolt-optimize-background-carousel-7937693282089218174

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
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request effectively optimizes the BackgroundCarousel component by reducing the number of rendered Next/Image components and scoping the ken-burns animation to active slides. This significantly improves performance by reducing DOM nodes, network requests, and CPU/GPU usage. The changes are well-implemented and address the identified performance bottlenecks.

}}
loop={true}
onSwiper={() => {}}
onSlideChange={(swiper) => setActiveIndex(swiper.realIndex)}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The onSwiper prop is currently an empty function. While it might be a placeholder, it's good practice to remove unused event handlers or provide a comment explaining its purpose if it's intentionally left empty for future use. An empty function still creates a new function on every render, which can have a minor performance impact.

Suggested change
onSlideChange={(swiper) => setActiveIndex(swiper.realIndex)}
onSwiper={(swiper) => { /* TODO: Add swiper initialization logic if needed */ }}

</div>
{shouldRenderSlide(index) ? (
<div className={`background-carousel__slide ${prefersReducedMotion ? "" : "ken-burns"}`}>
<Image src={image} alt="Conference venue background" fill priority={index === 0} sizes="100vw" style={{ objectFit: "cover" }} quality={85} />
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The priority prop for Next/Image is set to index === 0. While this is correct for the initial load, as slides change, the priority image might not be the currently active one. This could lead to less optimal loading of subsequent active images. Consider dynamically setting priority based on activeIndex to ensure the currently visible image always has priority.

Suggested change
<Image src={image} alt="Conference venue background" fill priority={index === 0} sizes="100vw" style={{ objectFit: "cover" }} quality={85} />
<Image src={image} alt="Conference venue background" fill priority={index === activeIndex} sizes="100vw" style={{ objectFit: "cover" }} quality={85} />


.swiper-slide-active,
.swiper-slide-duplicate-active,
.swiper-slide-prev {
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The selector .swiper-slide-prev is included here to apply the kenBurns animation. However, the shouldRenderSlide logic in BackgroundCarousel.tsx also renders the prevIndex. This means the animation will apply to the previous slide as well. If the intention is to only animate the active slide, then .swiper-slide-prev should be removed from this selector. If the intention is to animate the previous, active, and next slides, then this is correct, but it's worth clarifying the animation behavior for these slides.

- Implements lazy rendering in BackgroundCarousel to only mount active/prev/next slides (reduces images from 15 to 3).
- Scopes expensive ken-burns CSS animation to visible slides.
- Fixes Cypress test `home-editions.cy.ts` by replacing missing `h5` selector with `.hero8-header__event-line`.

Co-authored-by: anyulled <100741+anyulled@users.noreply.github.com>
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.

🧹 Nitpick comments (1)
cypress/e2e/home/home-editions.cy.ts (1)

14-14: LGTM — using the scoped BEM class is more resilient than the generic h5 tag.

The tighter selector correctly reflects the component's actual DOM structure, avoiding false matches from any other h5 headings that may or may not exist on the page. With lazy rendering now capping rendered slides at 3 (active + prev + next), the at.least: 2 threshold is still satisfied on initial mount since all three slots are populated synchronously.

One minor note: the inner cy.get(".hero8-header__event-line") inherits the global Cypress default assertion timeout (4 s) rather than the explicit 30 s set on the parent .hero8-header selector. If the event-line elements are ever part of a lazily-hydrated region, that mismatch could cause intermittent flakiness. Consider propagating an explicit timeout:

🔧 Optional: explicit timeout on inner assertion
-        cy.get(".hero8-header__event-line").should("have.length.at.least", 2);
+        cy.get(".hero8-header__event-line", { timeout: 30000 }).should("have.length.at.least", 2);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cypress/e2e/home/home-editions.cy.ts` at line 14, The inner selector
cy.get(".hero8-header__event-line") uses the global default timeout (4s) and may
be flaky if the region is lazily hydrated; update the assertion to pass an
explicit timeout (30_000 ms) matching the parent ".hero8-header" call so the
inner presence check uses the same 30s window (locate the
cy.get(".hero8-header__event-line") line and add the timeout option to the
get/assert invocation).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@cypress/e2e/home/home-editions.cy.ts`:
- Line 14: The inner selector cy.get(".hero8-header__event-line") uses the
global default timeout (4s) and may be flaky if the region is lazily hydrated;
update the assertion to pass an explicit timeout (30_000 ms) matching the parent
".hero8-header" call so the inner presence check uses the same 30s window
(locate the cy.get(".hero8-header__event-line") line and add the timeout option
to the get/assert invocation).
ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26b449e and 9a935e8.

📒 Files selected for processing (1)
  • cypress/e2e/home/home-editions.cy.ts

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.

1 participant