Skip to content

Add open-source contributor strip to network section#75

Open
adamsoffer wants to merge 6 commits into
mainfrom
claude/sad-pasteur-0241dd
Open

Add open-source contributor strip to network section#75
adamsoffer wants to merge 6 commits into
mainfrom
claude/sad-pasteur-0241dd

Conversation

@adamsoffer
Copy link
Copy Markdown
Collaborator

@adamsoffer adamsoffer commented Jun 3, 2026

What

Adds a contributor spotlight at the bottom of the "Powered by independent GPU providers" section on the homepage. It's a single row of the top 16 Livepeer GitHub contributors (by contributions over the last 12 months), followed by a one-line "Built in the open by 262 contributors. Contribute on GitHub →".

  • Avatars are grayscale and colorize + lift slightly on hover.
  • Each avatar links to the contributor's GitHub profile, with a name + contribution-count tooltip.
  • Separated from the Discord/Forum/Roadmap cards by a thin divider, and reuses the section's existing Framer Motion fade/stagger.

Why

It serves as a quiet, concrete proof point for the "builders and engineers who run the network and shape its direction. Open-source." copy directly above it — putting real faces behind the network claim without adding a heavy new marketing section.

Notes for reviewers

  • Contributor data is a static snapshot in lib/contributors.ts, sourced from spotlight.livepeer.dev/api/contributors (snapshot 2026-06-02). This follows the site's no-CMS / minimal-runtime-fetch conventions; the file documents how to refresh it.
  • Uses raw <img> tags (per project convention — no next/image) pointing at GitHub's avatar CDN with a sized &s= param.
  • No new dependencies. Production build passes; homepage still prerenders static.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an animated contributor strip: featured avatars (first 12), GitHub profile links, a “+N more” badge, total contributor count, and a “Contribute on GitHub” call-to-action.
    • Headline now cycles rotating words for a dynamic “Powered by …” display with motion-respectful fallback.
  • Style

    • Adjusted hero top padding and introduced a lighter overlay opacity variant for light mode.

Adds an understated contributor spotlight at the bottom of the "Powered
by independent GPU providers" (CommunityCTA) section — a row of the top
16 GitHub contributors over the last 12 months plus a "Contribute on
GitHub" link. Avatars are grayscale and colorize on hover, each linking
to the contributor's profile.

Serves as a quiet proof point for the "builders and engineers who run the
network" copy directly above it.

Contributor data is a static snapshot in lib/contributors.ts (sourced
from spotlight.livepeer.dev), keeping with the site's no-CMS /
minimal-runtime-fetch conventions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

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

Project Deployment Actions Updated (UTC)
website Ready Ready Preview, Comment Jun 3, 2026 7:16pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a static contributor snapshot module and a CyclingWords UI, updates CommunityCTA to import contributor data and CyclingWords, compute a 12-item spotlight, tweak hero layout/overlay classes, replace a static emphasis with rotating words, and render an animated GitHub-linked contributor strip with total contributor count and a "Contribute on GitHub" CTA.

Changes

Open-Source Contributor Showcase

Layer / File(s) Summary
Contributor data schema and snapshot
lib/contributors.ts
New module defines Contributor type with login, optional displayName, avatar, yearly, total, and core. Exports CONTRIBUTOR_STATS (aggregate totals) and CONTRIBUTORS (ranked hardcoded contributor records).
CyclingWords UI component
components/ui/CyclingWords.tsx
Adds a client-side Framer Motion component that cycles through provided words, respects prefers-reduced-motion, and supports an optional static suffix.
CommunityCTA helpers, layout tweaks, and contributor strip
components/home/CommunityCTA.tsx
Imports contributor data and CyclingWords, adds helpers to size avatar URLs and choose display names, changes hero padding to py-24 lg:py-32, adds light:opacity-[0.045] to the overlay mask, replaces the static phrase with CyclingWords, derives spotlightAvatars and remainingContributors, and inserts an animated contributor strip rendering GitHub-linked avatars, a “+N more” badge, and a total contributors CTA.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hop along the spotlight row, small avatars in tow,
Little links to open code where shared ideas grow,
Twelve faces leading, many more behind the door,
Click, contribute, and watch the garden roar,
A twitch of whiskers, the project's heart beats more.

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding a contributor strip to the community section of the homepage, which matches the primary objective of the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/sad-pasteur-0241dd

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
Copy Markdown

@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 (2)
components/home/CommunityCTA.tsx (2)

14-17: 💤 Low value

Consider co-locating the contributorName helper with the type definition.

The contributorName function is a utility specific to the Contributor type. Moving it to lib/contributors.ts would improve cohesion and allow reuse if other components need to display contributor names.

Note: The check for name !== "-" is defensive but harmless; the current data only contains null values, not "-".

🤖 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 `@components/home/CommunityCTA.tsx` around lines 14 - 17, Move the
contributorName helper closer to the Contributor type by relocating the function
contributorName (and its sizedAvatar if desired) from
components/home/CommunityCTA.tsx into lib/contributors.ts where the Contributor
type is defined; update CommunityCTA imports to import contributorName from
lib/contributors.ts and ensure the function signature remains contributorName(c:
Contributor) so other components can reuse it and type-checking remains intact.

205-205: 💤 Low value

Consider formatting the contributor count for consistency.

Line 188 uses .toLocaleString() to format the contribution count, but line 205 displays CONTRIBUTOR_STATS.contributors (262) without formatting. While 262 doesn't require thousands separators, applying .toLocaleString() would maintain consistency with the formatting pattern used elsewhere in the component.

♻️ Proposed change for consistency
-                {CONTRIBUTOR_STATS.contributors} contributors
+                {CONTRIBUTOR_STATS.contributors.toLocaleString()} contributors
🤖 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 `@components/home/CommunityCTA.tsx` at line 205, The contributor count is
displayed raw as CONTRIBUTORS_STATS.contributors; update the CommunityCTA.tsx
rendering to format the number consistently by calling
CONTRIBUTOR_STATS.contributors.toLocaleString() where the JSX currently renders
"{CONTRIBUTOR_STATS.contributors}" (same component that already uses
.toLocaleString() for contributions), so the contributors count uses the same
localized formatting pattern.
🤖 Prompt for all review comments with 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.

Nitpick comments:
In `@components/home/CommunityCTA.tsx`:
- Around line 14-17: Move the contributorName helper closer to the Contributor
type by relocating the function contributorName (and its sizedAvatar if desired)
from components/home/CommunityCTA.tsx into lib/contributors.ts where the
Contributor type is defined; update CommunityCTA imports to import
contributorName from lib/contributors.ts and ensure the function signature
remains contributorName(c: Contributor) so other components can reuse it and
type-checking remains intact.
- Line 205: The contributor count is displayed raw as
CONTRIBUTORS_STATS.contributors; update the CommunityCTA.tsx rendering to format
the number consistently by calling
CONTRIBUTOR_STATS.contributors.toLocaleString() where the JSX currently renders
"{CONTRIBUTOR_STATS.contributors}" (same component that already uses
.toLocaleString() for contributions), so the contributors count uses the same
localized formatting pattern.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2f5e1ae4-02be-4865-8cb2-7835c2910220

📥 Commits

Reviewing files that changed from the base of the PR and between 083f62b and c897dab.

📒 Files selected for processing (2)
  • components/home/CommunityCTA.tsx
  • lib/contributors.ts

The B&W terminal video sits at 15% opacity, which reads as subtle texture
in dark mode but became an unbalanced dark/green smear over the light
background. Make it theme-aware (light:opacity-[0.045]) so light mode reads
clean; dark mode is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tor cluster

- Reduce section padding (py-32/44 -> py-24/32) so the content no longer
  strands above a large gap before the footer.
- Remove the redundant divider above the contributor strip; the footer's
  own top divider is the single boundary (no more double rule).
- Pull the contributor strip up close to the resource cards so the cards
  and the people read as one community hub.
- Replace the wide evenly-spaced avatar row with a compact overlapping
  cluster (ring-separated, hover lifts/colorizes) plus a "+N more" chip
  linking to GitHub.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Raise the "Built in the open by..." caption to foreground/90 so it no
  longer washes out against the background texture; emphasize the count
  at full weight.
- Style "Contribute on GitHub" as an underlined link that turns green on
  hover (rather than green at rest), so it reads as a link without
  competing for attention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with 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.

Inline comments:
In `@components/home/CommunityCTA.tsx`:
- Around line 224-231: The hover classes on the anchor in the CommunityCTA
component use a non-approved token `green-bright` (see the <a> element with
href={EXTERNAL_LINKS.github}); replace `hover:text-green-bright` and
`hover:decoration-green-bright` with an allowed theme token such as
`hover:text-green` and `hover:decoration-green` (or `green-light` if you prefer
a lighter hover) so the class names comply with the approved theme tokens.
- Around line 186-216: In CommunityCTA, replace the invalid theme token usage in
the contributor count anchor (the className containing
"hover:text-green-bright") with an allowed token (e.g., "hover:text-green" or
"hover:text-green-light"); update the class string on that <a> (the element that
renders "+{remainingContributors}") to use the permitted token so the hover
color uses a valid theme variable instead of "green-bright".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0293c869-7ef9-4184-a2d0-4020b2971b41

📥 Commits

Reviewing files that changed from the base of the PR and between 6463cbe and 54f2845.

📒 Files selected for processing (1)
  • components/home/CommunityCTA.tsx

Comment on lines +186 to +216
<div className="flex items-center justify-center">
{spotlightAvatars.map((c, i) => (
<a
key={c.login}
href={`https://github.com/${c.login}`}
target="_blank"
rel="noopener noreferrer"
title={`${contributorName(c)} · ${c.yearly.toLocaleString()} contributions`}
style={{ zIndex: spotlightAvatars.length - i }}
className="group relative -ml-2 transition-transform duration-200 first:ml-0 hover:z-20 hover:-translate-y-1"
>
<img
src={sizedAvatar(c.avatar, 96)}
alt={contributorName(c)}
width={40}
height={40}
loading="lazy"
className="h-10 w-10 rounded-full object-cover ring-2 ring-background grayscale transition duration-200 group-hover:scale-110 group-hover:grayscale-0 group-hover:ring-green/60"
/>
</a>
))}
<a
href={EXTERNAL_LINKS.github}
target="_blank"
rel="noopener noreferrer"
title={`+${remainingContributors} more contributors`}
style={{ zIndex: 0 }}
className="-ml-2 flex h-10 w-10 items-center justify-center rounded-full bg-foreground/[0.06] font-mono text-[10px] font-medium text-foreground/60 ring-2 ring-background transition-colors duration-200 hover:bg-foreground/[0.1] hover:text-green-bright"
>
+{remainingContributors}
</a>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace green-bright with an allowed theme token.

Line 213 uses hover:text-green-bright, but green-bright is not in the allowed theme token list. As per coding guidelines, use one of: green, green-light, or green-dark.

🎨 Proposed fix using allowed theme token
-                className="-ml-2 flex h-10 w-10 items-center justify-center rounded-full bg-foreground/[0.06] font-mono text-[10px] font-medium text-foreground/60 ring-2 ring-background transition-colors duration-200 hover:bg-foreground/[0.1] hover:text-green-bright"
+                className="-ml-2 flex h-10 w-10 items-center justify-center rounded-full bg-foreground/[0.06] font-mono text-[10px] font-medium text-foreground/60 ring-2 ring-background transition-colors duration-200 hover:bg-foreground/[0.1] hover:text-green"

Alternative: use green-light if you need a lighter shade.

As per coding guidelines: Use theme tokens for colors (green, green-light, green-dark, blue, blue-light, blue-dark, dark, dark-lighter, dark-card, dark-border) instead of creating new color variants.

🤖 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 `@components/home/CommunityCTA.tsx` around lines 186 - 216, In CommunityCTA,
replace the invalid theme token usage in the contributor count anchor (the
className containing "hover:text-green-bright") with an allowed token (e.g.,
"hover:text-green" or "hover:text-green-light"); update the class string on that
<a> (the element that renders "+{remainingContributors}") to use the permitted
token so the hover color uses a valid theme variable instead of "green-bright".

Comment on lines +224 to +231
<a
href={EXTERNAL_LINKS.github}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 font-medium text-foreground underline decoration-foreground/30 underline-offset-4 transition-colors duration-200 hover:text-green-bright hover:decoration-green-bright"
>
Contribute on GitHub <span aria-hidden="true">→</span>
</a>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace green-bright with an allowed theme token.

Line 228 uses hover:text-green-bright and hover:decoration-green-bright, but green-bright is not in the allowed theme token list. As per coding guidelines, use one of: green, green-light, or green-dark.

🎨 Proposed fix using allowed theme token
-                className="inline-flex items-center gap-1 font-medium text-foreground underline decoration-foreground/30 underline-offset-4 transition-colors duration-200 hover:text-green-bright hover:decoration-green-bright"
+                className="inline-flex items-center gap-1 font-medium text-foreground underline decoration-foreground/30 underline-offset-4 transition-colors duration-200 hover:text-green hover:decoration-green"

Alternative: use green-light if you prefer a lighter shade on hover.

As per coding guidelines: Use theme tokens for colors (green, green-light, green-dark, blue, blue-light, blue-dark, dark, dark-lighter, dark-card, dark-border) instead of creating new color variants.

📝 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
<a
href={EXTERNAL_LINKS.github}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 font-medium text-foreground underline decoration-foreground/30 underline-offset-4 transition-colors duration-200 hover:text-green-bright hover:decoration-green-bright"
>
Contribute on GitHub <span aria-hidden="true"></span>
</a>
<a
href={EXTERNAL_LINKS.github}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1 font-medium text-foreground underline decoration-foreground/30 underline-offset-4 transition-colors duration-200 hover:text-green hover:decoration-green"
>
Contribute on GitHub <span aria-hidden="true"></span>
</a>
🤖 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 `@components/home/CommunityCTA.tsx` around lines 224 - 231, The hover classes
on the anchor in the CommunityCTA component use a non-approved token
`green-bright` (see the <a> element with href={EXTERNAL_LINKS.github}); replace
`hover:text-green-bright` and `hover:decoration-green-bright` with an allowed
theme token such as `hover:text-green` and `hover:decoration-green` (or
`green-light` if you prefer a lighter hover) so the class names comply with the
approved theme tokens.

Add a reusable CyclingWords component that swaps the final word of the
"Powered by independent ___" heading on a vertical fade/slide/blur cadence
(GPU providers / video engineers / builders), rendered in the brand green
gradient. The word sits on its own centered line so the rest of the heading
never reflows, and it holds static under prefers-reduced-motion.

- 4s interval per word.
- Bottom padding (with compensating negative margin) so descenders aren't
  clipped by the blur filter / gradient text clip.
- Brighten the "The Network" eyebrow (foreground/30 -> /60) so it reads in
  both themes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with 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.

Inline comments:
In `@components/ui/CyclingWords.tsx`:
- Around line 24-25: The CyclingWords component currently accesses words[index]
which can be undefined when the words prop is empty; add a runtime guard in the
component (e.g., in the render/JSX and any place using words[index]) to return a
safe fallback (empty string or a default word) or short-circuit rendering when
words.length === 0, or alternatively enforce a non-empty array via prop
validation/TypeScript utility type; update references to words[index] (and any
use in state/interval logic) to use a safe accessor like words[index] ?? '' so
the component never renders undefined.
- Around line 42-50: The CyclingWords component mounts motion.span with animated
initial/animate/exit values even when reduced motion is requested; update the
logic in components/ui/CyclingWords.tsx (the CyclingWords component and its
motion.span/AnimatePresence usage) to respect useReducedMotion(): when
useReducedMotion() is true, render non-animated values (e.g., set
initial/animate/exit to static states or omit them and set transition to {
duration: 0 }) or render a plain span instead of AnimatePresence/motion.span so
no y-translate/blur/opacity transitions occur; ensure the setInterval stop
remains, and adjust the motion.span props (initial, animate, exit, transition)
and/or conditionally render to short-circuit animations when reduced motion is
enabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b8e02a81-0122-4f26-99a2-72a4a1bc9df4

📥 Commits

Reviewing files that changed from the base of the PR and between 54f2845 and 0b335fe.

📒 Files selected for processing (2)
  • components/home/CommunityCTA.tsx
  • components/ui/CyclingWords.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/home/CommunityCTA.tsx

Comment on lines +24 to +25
words: string[];
suffix?: string;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle empty words input to avoid rendering undefined.

If words is empty, words[index] is undefined. Add a runtime guard (or enforce non-empty type) so this component fails safe.

Suggested fix
 export default function CyclingWords({
   words,
@@
 }) {
+  if (words.length === 0) return null;
+
   const [index, setIndex] = useState(0);

Also applies to: 51-51

🤖 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 `@components/ui/CyclingWords.tsx` around lines 24 - 25, The CyclingWords
component currently accesses words[index] which can be undefined when the words
prop is empty; add a runtime guard in the component (e.g., in the render/JSX and
any place using words[index]) to return a safe fallback (empty string or a
default word) or short-circuit rendering when words.length === 0, or
alternatively enforce a non-empty array via prop validation/TypeScript utility
type; update references to words[index] (and any use in state/interval logic) to
use a safe accessor like words[index] ?? '' so the component never renders
undefined.

Comment on lines +42 to +50
<AnimatePresence mode="popLayout" initial={false}>
<motion.span
key={index}
className={`inline-block whitespace-nowrap pb-[0.18em] ${className}`}
initial={{ y: "0.55em", opacity: 0, filter: "blur(6px)" }}
animate={{ y: 0, opacity: 1, filter: "blur(0px)" }}
exit={{ y: "-0.55em", opacity: 0, filter: "blur(6px)" }}
transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify reduced-motion handling paths in CyclingWords and locate all useReducedMotion callsites.
# Expected: component should branch animation props or render non-animated span when reduce=true.

rg -n -C3 '\buseReducedMotion\s*\(' --type=tsx
rg -n -C5 'initial=\{|animate=\{|exit=\{' --type=tsx

Repository: livepeer/website

Length of output: 116


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect the component implementation around the cited lines
sed -n '1,220p' components/ui/CyclingWords.tsx

# 2) Re-run searches across the repo for useReducedMotion and motion initial/animate/exit
rg -n '\buseReducedMotion\s*\(' components/ui components/home app --hidden || true
rg -n 'initial=\{|animate=\{|exit=\{' components/ui components/home app --hidden || true

# 3) Find callsites of CyclingWords to confirm prop shapes used in app/home code
rg -n '\b<CyclingWords\b' --hidden . || true

Repository: livepeer/website

Length of output: 5073


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Locate all callsites of CyclingWords and show the prop(s) passed for words/reduce-related behavior
rg -n --hidden '<CyclingWords\b' components app || true

# 2) Check whether the repo sets a global Framer Motion reducedMotion policy (MotionConfig / reducedMotion)
rg -n --hidden 'MotionConfig|reducedMotion' . --glob '*.{ts,tsx,js,jsx}' || true

# 3) Double-check if any CSS blanket disables motion/animations for reduced motion in globals.css
rg -n --hidden 'prefers-reduced-motion' globals.css components app . || true

Repository: livepeer/website

Length of output: 1672


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show CyclingWords usage in CommunityCTA
sed -n '110,175p' components/home/CommunityCTA.tsx

echo "----"

# Show reduced motion CSS block
sed -n '690,760p' app/globals.css

echo "----"

# Search for Framer Motion MotionConfig / reducedMotion policy
rg -n --hidden 'MotionConfig|reducedMotion' . --glob '*.{ts,tsx,js,jsx}' || true

echo "----"

# Search for any other useReducedMotion usage in repo
rg -n --hidden '\buseReducedMotion\s*\(' . --glob '*.{ts,tsx,js,jsx}' || true

Repository: livepeer/website

Length of output: 3657


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show CyclingWords usage in CommunityCTA
sed -n '110,175p' components/home/CommunityCTA.tsx

echo "----"

# Show reduced motion CSS block
sed -n '690,760p' app/globals.css

echo "----"

# Search for Framer Motion MotionConfig / reducedMotion policy
rg -n --hidden 'MotionConfig|reducedMotion' . --glob '*.{ts,tsx,js,jsx}' || true

echo "----"

# Search for any other useReducedMotion usage in repo
rg -n --hidden '\buseReducedMotion\s*\(' . --glob '*.{ts,tsx,js,jsx}' || true

Repository: livepeer/website

Length of output: 3657


Fix reduced-motion handling in components/ui/CyclingWords.tsx

useReducedMotion() only stops cycling in the setInterval; the component still mounts motion.span with initial/animate blur + y-translate, so reduced-motion users can still get the initial transition (even though app/globals.css also shortens animations/transitions under prefers-reduced-motion).

<AnimatePresence mode="popLayout" initial={false}>
  <motion.span
    key={index}
    className={`inline-block whitespace-nowrap pb-[0.18em] ${className}`}
    initial={{ y: "0.55em", opacity: 0, filter: "blur(6px)" }}
    animate={{ y: 0, opacity: 1, filter: "blur(0px)" }}
    exit={{ y: "-0.55em", opacity: 0, filter: "blur(6px)" }}
    transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
  >
Suggested fix
-      <AnimatePresence mode="popLayout" initial={false}>
-        <motion.span
-          key={index}
-          className={`inline-block whitespace-nowrap pb-[0.18em] ${className}`}
-          initial={{ y: "0.55em", opacity: 0, filter: "blur(6px)" }}
-          animate={{ y: 0, opacity: 1, filter: "blur(0px)" }}
-          exit={{ y: "-0.55em", opacity: 0, filter: "blur(6px)" }}
-          transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
-        >
-          {words[index]}
-        </motion.span>
-      </AnimatePresence>
+      {reduce ? (
+        <span className={`inline-block whitespace-nowrap pb-[0.18em] ${className}`}>
+          {words[index]}
+        </span>
+      ) : (
+        <AnimatePresence mode="popLayout" initial={false}>
+          <motion.span
+            key={index}
+            className={`inline-block whitespace-nowrap pb-[0.18em] ${className}`}
+            initial={{ y: "0.55em", opacity: 0, filter: "blur(6px)" }}
+            animate={{ y: 0, opacity: 1, filter: "blur(0px)" }}
+            exit={{ y: "-0.55em", opacity: 0, filter: "blur(6px)" }}
+            transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
+          >
+            {words[index]}
+          </motion.span>
+        </AnimatePresence>
+      )}
🤖 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 `@components/ui/CyclingWords.tsx` around lines 42 - 50, The CyclingWords
component mounts motion.span with animated initial/animate/exit values even when
reduced motion is requested; update the logic in components/ui/CyclingWords.tsx
(the CyclingWords component and its motion.span/AnimatePresence usage) to
respect useReducedMotion(): when useReducedMotion() is true, render non-animated
values (e.g., set initial/animate/exit to static states or omit them and set
transition to { duration: 0 }) or render a plain span instead of
AnimatePresence/motion.span so no y-translate/blur/opacity transitions occur;
ensure the setInterval stop remains, and adjust the motion.span props (initial,
animate, exit, transition) and/or conditionally render to short-circuit
animations when reduced motion is enabled.

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