Description
When the SVG card is embedded as an <img> in a GitHub profile README, GitHub renders it through a sandboxed proxy (camo) where CSS animations do not execute. The card is frozen at currentTime: 0 — the very start of all @keyframe animations.
This causes the .rating-circle to render with stroke-dashoffset: 250 (the from value), which is equal to the stroke-dasharray: 250. Because the stroke-dasharray value (250) doesn't precisely match the circle's actual circumference (2π × 38 ≈ 238.76 px), the arc appears at an incorrect position — showing a strangely clipped or offset partial arc rather than being invisible (as intended before animation runs) or fully drawn (as intended after animation completes).
Steps to Reproduce
- Add
 to a GitHub profile README.
-
- View the profile page on GitHub.
-
- The rating circle arc appears broken/misaligned.
You can also observe it by loading the SVG URL directly and checking animation state:
document.querySelector('.rating-circle').getAnimations()
// → [{ animationName: 'ratingProgressAnimation', playState: 'running', currentTime: 0 }]
// currentTime never advances — animations are frozen
Root Cause
In src/CardTemplates.js, the .rating-circle CSS class has:
.rating-circle {
stroke-dasharray: 250;
/* No stroke-dashoffset set here — defaults to 0 */
animation: ratingProgressAnimation 1s forwards ease-in-out;
}
@keyframes ratingProgressAnimation {
from { stroke-dashoffset: 250; }
to { stroke-dashoffset: <rating-progress-value>; }
}
When animations don't run, the element uses its base CSS stroke-dashoffset: 0 (default), NOT the from keyframe value. So depending on the renderer, the arc either shows fully drawn (dashoffset 0 = full circle) or at the wrong position.
Additionally, stroke-dasharray: 250 does not match the real circumference of the circle (r=38, circumference ≈ 238.76), compounding the visual glitch.
Proposed Fix
Set the pre-animation final state directly on the element so the frozen/static rendering already looks correct. Move the stroke-dashoffset out of @keyframes from {} and into the base class, using the per-grade final value:
.rating-circle {
stroke-dasharray: 238.76; /* match actual circumference: 2π × 38 */
stroke-dashoffset: <ratingsProgress>; /* set directly — no need for a "from" keyframe */
animation: ratingProgressAnimation 1s forwards ease-in-out;
}
@keyframes ratingProgressAnimation {
from { stroke-dashoffset: 238.76; } /* start fully hidden */
to { stroke-dashoffset: <ratingsProgress>; }
}
Since ratingsProgress is already a template variable injected per-request (e.g. ${ratingsProgress}), simply adding stroke-dashoffset: ${ratingsProgress}; directly to .rating-circle in CardTemplates.js means the static/frozen state already shows the correct arc fill.
The same fix also applies to the transform-origin for the rotation — using cx/cy coordinates of 0 0 (or matching the actual circle center) would make the geometry cleaner.
Impact
All users embedding this card in GitHub READMEs see a broken rating circle. The fix is a one-line addition to CardTemplates.js with no breaking changes.
Reference
src/CardTemplates.js — .rating-circle CSS class and ratingProgressAnimation keyframes
-
- Circle element:
<circle cx="-10" cy="8" r="38" />
-
-
- Actual circumference:
2 × π × 38 ≈ 238.76
Description
When the SVG card is embedded as an
<img>in a GitHub profile README, GitHub renders it through a sandboxed proxy (camo) where CSS animations do not execute. The card is frozen atcurrentTime: 0— the very start of all@keyframeanimations.This causes the
.rating-circleto render withstroke-dashoffset: 250(thefromvalue), which is equal to thestroke-dasharray: 250. Because thestroke-dasharrayvalue (250) doesn't precisely match the circle's actual circumference (2π × 38 ≈ 238.76 px), the arc appears at an incorrect position — showing a strangely clipped or offset partial arc rather than being invisible (as intended before animation runs) or fully drawn (as intended after animation completes).Steps to Reproduce
to a GitHub profile README.You can also observe it by loading the SVG URL directly and checking animation state:
Root Cause
In
src/CardTemplates.js, the.rating-circleCSS class has:When animations don't run, the element uses its base CSS
stroke-dashoffset: 0(default), NOT thefromkeyframe value. So depending on the renderer, the arc either shows fully drawn (dashoffset 0 = full circle) or at the wrong position.Additionally,
stroke-dasharray: 250does not match the real circumference of the circle (r=38, circumference ≈ 238.76), compounding the visual glitch.Proposed Fix
Set the pre-animation final state directly on the element so the frozen/static rendering already looks correct. Move the
stroke-dashoffsetout of@keyframes from {}and into the base class, using the per-grade final value:Since
ratingsProgressis already a template variable injected per-request (e.g.${ratingsProgress}), simply addingstroke-dashoffset: ${ratingsProgress};directly to.rating-circleinCardTemplates.jsmeans the static/frozen state already shows the correct arc fill.The same fix also applies to the
transform-originfor the rotation — usingcx/cycoordinates of0 0(or matching the actual circle center) would make the geometry cleaner.Impact
All users embedding this card in GitHub READMEs see a broken rating circle. The fix is a one-line addition to
CardTemplates.jswith no breaking changes.Reference
src/CardTemplates.js—.rating-circleCSS class andratingProgressAnimationkeyframes<circle cx="-10" cy="8" r="38" />2 × π × 38 ≈ 238.76