Add open-source contributor strip to network section#75
Conversation
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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds 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. ChangesOpen-Source Contributor Showcase
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
components/home/CommunityCTA.tsx (2)
14-17: 💤 Low valueConsider co-locating the
contributorNamehelper with the type definition.The
contributorNamefunction is a utility specific to theContributortype. Moving it tolib/contributors.tswould 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 containsnullvalues, 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 valueConsider formatting the contributor count for consistency.
Line 188 uses
.toLocaleString()to format the contribution count, but line 205 displaysCONTRIBUTOR_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
📒 Files selected for processing (2)
components/home/CommunityCTA.tsxlib/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>
There was a problem hiding this comment.
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
📒 Files selected for processing (1)
components/home/CommunityCTA.tsx
| <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> |
There was a problem hiding this comment.
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".
| <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> |
There was a problem hiding this comment.
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.
| <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>
There was a problem hiding this comment.
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
📒 Files selected for processing (2)
components/home/CommunityCTA.tsxcomponents/ui/CyclingWords.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- components/home/CommunityCTA.tsx
| words: string[]; | ||
| suffix?: string; |
There was a problem hiding this comment.
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.
| <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] }} | ||
| > |
There was a problem hiding this comment.
🧩 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=tsxRepository: 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 . || trueRepository: 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 . || trueRepository: 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}' || trueRepository: 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}' || trueRepository: 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.
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 →".
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
lib/contributors.ts, sourced fromspotlight.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.<img>tags (per project convention — nonext/image) pointing at GitHub's avatar CDN with a sized&s=param.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Style