@@ -32,38 +32,43 @@ export class CardRenderer {
3232 const x = Math . random ( ) * width ;
3333 const y = Math . random ( ) * height ;
3434 const r = Math . random ( ) * 1.5 + 0.5 ;
35- const opacity = Math . random ( ) * 0.7 + 0.3 ;
35+ const opacity = + ( Math . random ( ) * 0.7 + 0.3 ) . toFixed ( 2 ) ;
36+ const opacityLow = + ( opacity * 0.3 ) . toFixed ( 2 ) ;
3637 const twinkleDur = ( Math . random ( ) * 3 + 2 ) . toFixed ( 1 ) ; // 2-5 seconds
3738 const moveX = ( Math . random ( ) * 4 - 2 ) . toFixed ( 1 ) ; // -2 to +2
3839 const moveY = ( Math . random ( ) * 4 - 2 ) . toFixed ( 1 ) ; // -2 to +2
3940 const delay = ( Math . random ( ) * 3 ) . toFixed ( 1 ) ;
40- return `<circle cx="${ x } " cy="${ y } " r="${ r } " fill="#fff" opacity="${ opacity } ">
41- <animate attributeName="opacity" values="${ opacity } ;${ opacity * 0.3 } ;${ opacity } " dur="${ twinkleDur } s" begin="${ delay } s" repeatCount="indefinite"/>
42- <animateTransform attributeName="transform" type="translate" values="0,0; ${ moveX } ,${ moveY } ; 0,0" dur="${ parseFloat ( twinkleDur ) * 2 } s" begin="${ delay } s" repeatCount="indefinite"/>
41+ return `<circle cx="${ x . toFixed ( 1 ) } " cy="${ y . toFixed ( 1 ) } " r="${ r . toFixed ( 1 ) } " fill="#fff" opacity="${ opacity } ">
42+ <animate attributeName="opacity" values="${ opacity } ;${ opacityLow } ;${ opacity } " dur="${ twinkleDur } s" begin="${ delay } s" repeatCount="indefinite" />
43+ <animateTransform attributeName="transform" type="translate" values="0,0; ${ moveX } ,${ moveY } ; 0,0" dur="${ parseFloat ( twinkleDur ) * 2 } s" begin="${ delay } s" repeatCount="indefinite" />
4344 </circle>` ;
4445 } ) . join ( '' ) ;
4546
4647 // Generate shooting stars
4748 const shootingStars = Array . from ( { length : 3 } , ( _ , i ) => {
48- const startX = Math . random ( ) * width ;
49- const startY = Math . random ( ) * ( height / 2 ) ;
50- const endX = startX + 200 + Math . random ( ) * 100 ;
51- const endY = startY + 150 + Math . random ( ) * 50 ;
49+ const startX = ( Math . random ( ) * width ) . toFixed ( 1 ) ;
50+ const startY = ( Math . random ( ) * ( height / 2 ) ) . toFixed ( 1 ) ;
51+ const endX = ( parseFloat ( startX ) + 200 + Math . random ( ) * 100 ) . toFixed ( 1 ) ;
52+ const endY = ( parseFloat ( startY ) + 150 + Math . random ( ) * 50 ) . toFixed ( 1 ) ;
53+ const startX2 = ( parseFloat ( startX ) + 30 ) . toFixed ( 1 ) ;
54+ const startY2 = ( parseFloat ( startY ) + 20 ) . toFixed ( 1 ) ;
55+ const endX2 = ( parseFloat ( endX ) + 30 ) . toFixed ( 1 ) ;
56+ const endY2 = ( parseFloat ( endY ) + 20 ) . toFixed ( 1 ) ;
5257 const delay = ( i * 8 + Math . random ( ) * 4 ) . toFixed ( 1 ) ;
5358 return `
54- <line x1="${ startX } " y1="${ startY } " x2="${ startX + 30 } " y2="${ startY + 20 } " stroke="url(#shootingStarGradient)" stroke-width="2" opacity="0" stroke-linecap="round">
55- <animate attributeName="x1" values="${ startX } ;${ endX } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite"/>
56- <animate attributeName="y1" values="${ startY } ;${ endY } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite"/>
57- <animate attributeName="x2" values="${ startX + 30 } ;${ endX + 30 } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite"/>
58- <animate attributeName="y2" values="${ startY + 20 } ;${ endY + 20 } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite"/>
59- <animate attributeName="opacity" values="0;0.8;0" dur="1.5s" begin="${ delay } s" repeatCount="indefinite"/>
59+ <line x1="${ startX } " y1="${ startY } " x2="${ startX2 } " y2="${ startY2 } " stroke="url(#shootingStarGradient)" stroke-width="2" opacity="0" stroke-linecap="round">
60+ <animate attributeName="x1" values="${ startX } ;${ endX } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite" />
61+ <animate attributeName="y1" values="${ startY } ;${ endY } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite" />
62+ <animate attributeName="x2" values="${ startX2 } ;${ endX2 } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite" />
63+ <animate attributeName="y2" values="${ startY2 } ;${ endY2 } " dur="1.5s" begin="${ delay } s" repeatCount="indefinite" />
64+ <animate attributeName="opacity" values="0;0.8;0" dur="1.5s" begin="${ delay } s" repeatCount="indefinite" />
6065 </line>
6166 ` ;
6267 } ) . join ( '' ) ;
6368
6469 // Generate orbital rings
6570 const orbitRings = [ 120 , 160 , 200 , 240 ] . map ( ( r , i ) =>
66- `<circle cx="${ centerX } " cy="${ centerY } " r="${ r } " fill="none" stroke="rgba(0, 200, 255, ${ 0.15 - i * 0.03 } )" stroke-width="1" stroke-dasharray="10,8"/>`
71+ `<circle cx="${ centerX } " cy="${ centerY } " r="${ r } " fill="none" stroke="rgba(0, 200, 255, ${ ( 0.15 - i * 0.03 ) . toFixed ( 2 ) } )" stroke-width="1" stroke-dasharray="10,8" />`
6772 ) . join ( '' ) ;
6873
6974 // Generate data beams radiating from center
@@ -81,36 +86,38 @@ export class CardRenderer {
8186 const angle = ( stat . angle * Math . PI ) / 180 ;
8287 const intensity = maxValue > 0 ? stat . value / maxValue : 0 ;
8388 const beamLength = 100 + ( intensity * 140 ) ;
84- const endX = centerX + Math . cos ( angle ) * beamLength ;
85- const endY = centerY + Math . sin ( angle ) * beamLength ;
89+ const endX = ( centerX + Math . cos ( angle ) * beamLength ) . toFixed ( 1 ) ;
90+ const endY = ( centerY + Math . sin ( angle ) * beamLength ) . toFixed ( 1 ) ;
8691
8792 // Data point position
88- const dotX = centerX + Math . cos ( angle ) * ( beamLength + 20 ) ;
89- const dotY = centerY + Math . sin ( angle ) * ( beamLength + 20 ) ;
93+ const dotX = ( centerX + Math . cos ( angle ) * ( beamLength + 20 ) ) . toFixed ( 1 ) ;
94+ const dotY = ( centerY + Math . sin ( angle ) * ( beamLength + 20 ) ) . toFixed ( 1 ) ;
9095
9196 // Label position (further out)
92- const labelX = centerX + Math . cos ( angle ) * ( beamLength + 60 ) ;
97+ const labelX = ( centerX + Math . cos ( angle ) * ( beamLength + 60 ) ) . toFixed ( 1 ) ;
9398 const labelY = centerY + Math . sin ( angle ) * ( beamLength + 60 ) ;
99+ const labelYTop = ( labelY - 12 ) . toFixed ( 1 ) ;
100+ const labelYBottom = ( labelY + 6 ) . toFixed ( 1 ) ;
94101
95102 return `
96103 <!-- Beam line -->
97- <line x1="${ centerX } " y1="${ centerY } " x2="${ endX } " y2="${ endY } " stroke="url(#beamGradient${ i } )" stroke-width="2" opacity="0.6"/>
104+ <line x1="${ centerX } " y1="${ centerY } " x2="${ endX } " y2="${ endY } " stroke="url(#beamGradient${ i } )" stroke-width="2" opacity="0.6" />
98105
99106 <!-- Glow effect beam -->
100- <line x1="${ centerX } " y1="${ centerY } " x2="${ endX } " y2="${ endY } " stroke="rgba(0, 200, 255, 0.3)" stroke-width="6" filter="url(#glow)"/>
107+ <line x1="${ centerX } " y1="${ centerY } " x2="${ endX } " y2="${ endY } " stroke="rgba(0, 200, 255, 0.3)" stroke-width="6" filter="url(#glow)" />
101108
102109 <!-- Data point -->
103110 <circle cx="${ dotX } " cy="${ dotY } " r="6" fill="#00c8ff" filter="url(#glow)">
104- <animate attributeName="r" values="6;8;6" dur="2s" repeatCount="indefinite"/>
111+ <animate attributeName="r" values="6;8;6" dur="2s" repeatCount="indefinite" />
105112 </circle>
106113 <circle cx="${ dotX } " cy="${ dotY } " r="12" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.4">
107- <animate attributeName="r" values="12;16;12" dur="2s" repeatCount="indefinite"/>
108- <animate attributeName="opacity" values="0.4;0.1;0.4" dur="2s" repeatCount="indefinite"/>
114+ <animate attributeName="r" values="12;16;12" dur="2s" repeatCount="indefinite" />
115+ <animate attributeName="opacity" values="0.4;0.1;0.4" dur="2s" repeatCount="indefinite" />
109116 </circle>
110117
111118 <!-- Stat label -->
112- <text x="${ labelX } " y="${ labelY - 12 } " text-anchor="middle" fill="#00c8ff" font-size="11" font-weight="600" filter="url(#glow)">${ stat . label } </text>
113- <text x="${ labelX } " y="${ labelY + 6 } " text-anchor="middle" fill="#fff" font-size="20" font-weight="700" class="number" filter="url(#glow)">${ formatNumber ( stat . value ) } </text>
119+ <text x="${ labelX } " y="${ labelYTop } " text-anchor="middle" fill="#00c8ff" font-size="11" font-weight="600" filter="url(#glow)">${ stat . label } </text>
120+ <text x="${ labelX } " y="${ labelYBottom } " text-anchor="middle" fill="#fff" font-size="20" font-weight="700" class="number" filter="url(#glow)">${ formatNumber ( stat . value ) } </text>
114121 ` ;
115122 } ) . join ( '' ) ;
116123
@@ -219,7 +226,7 @@ export class CardRenderer {
219226 </style>
220227
221228 <!-- Space background -->
222- <rect width="${ width } " height="${ height } " fill="url(#spaceGradient)"/>
229+ <rect width="${ width } " height="${ height } " fill="url(#spaceGradient)" />
223230
224231 <!-- Starfield -->
225232 <g opacity="0.8">
@@ -232,7 +239,7 @@ export class CardRenderer {
232239 </g>
233240
234241 <!-- Scan lines -->
235- <rect width="${ width } " height="${ height } " fill="url(#scanlines)" opacity="0.3"/>
242+ <rect width="${ width } " height="${ height } " fill="url(#scanlines)" opacity="0.3" />
236243
237244 <!-- Rotating orbital rings -->
238245 <g class="rotating">
@@ -259,34 +266,34 @@ export class CardRenderer {
259266 <!-- Center sphere (Earth-like) -->
260267 <g filter="url(#strongGlow)">
261268 <!-- Avatar image -->
262- <image href="${ stats . avatarUrl } " x="${ centerX - 65 } " y="${ centerY - 65 } " width="130" height="130" clip-path="url(#avatarClip)" opacity="0.9"/>
269+ <image href="${ stats . avatarUrl } " x="${ centerX - 65 } " y="${ centerY - 65 } " width="130" height="130" clip-path="url(#avatarClip)" opacity="0.9" />
263270
264271 <!-- Avatar border and effects -->
265- <circle cx="${ centerX } " cy="${ centerY } " r="65" fill="none" stroke="#00c8ff" stroke-width="3" opacity="0.8"/>
266- <circle cx="${ centerX } " cy="${ centerY } " r="70" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.5"/>
267- <circle cx="${ centerX } " cy="${ centerY } " r="80" fill="none" stroke="#00c8ff" stroke-width="2" opacity="0.3"/>
268- <circle cx="${ centerX } " cy="${ centerY } " r="75" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.4" stroke-dasharray="4,4"/>
272+ <circle cx="${ centerX } " cy="${ centerY } " r="65" fill="none" stroke="#00c8ff" stroke-width="3" opacity="0.8" />
273+ <circle cx="${ centerX } " cy="${ centerY } " r="70" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.5" />
274+ <circle cx="${ centerX } " cy="${ centerY } " r="80" fill="none" stroke="#00c8ff" stroke-width="2" opacity="0.3" />
275+ <circle cx="${ centerX } " cy="${ centerY } " r="75" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.4" stroke-dasharray="4,4" />
269276
270277 <!-- Ping animation rings -->
271278 <circle cx="${ centerX } " cy="${ centerY } " r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0">
272- <animate attributeName="r" values="80;150;220" dur="5s" repeatCount="indefinite"/>
273- <animate attributeName="opacity" values="0.7;0.3;0" dur="5s" repeatCount="indefinite"/>
279+ <animate attributeName="r" values="80;150;220" dur="5s" repeatCount="indefinite" />
280+ <animate attributeName="opacity" values="0.7;0.3;0" dur="5s" repeatCount="indefinite" />
274281 </circle>
275282 <circle cx="${ centerX } " cy="${ centerY } " r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0">
276- <animate attributeName="r" values="80;150;220" dur="5s" begin="1s" repeatCount="indefinite"/>
277- <animate attributeName="opacity" values="0.7;0.3;0" dur="5s" begin="1s" repeatCount="indefinite"/>
283+ <animate attributeName="r" values="80;150;220" dur="5s" begin="1s" repeatCount="indefinite" />
284+ <animate attributeName="opacity" values="0.7;0.3;0" dur="5s" begin="1s" repeatCount="indefinite" />
278285 </circle>
279286 <circle cx="${ centerX } " cy="${ centerY } " r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0">
280- <animate attributeName="r" values="80;150;220" dur="5s" begin="2s" repeatCount="indefinite"/>
281- <animate attributeName="opacity" values="0.7;0.3;0" dur="5s" begin="2s" repeatCount="indefinite"/>
287+ <animate attributeName="r" values="80;150;220" dur="5s" begin="2s" repeatCount="indefinite" />
288+ <animate attributeName="opacity" values="0.7;0.3;0" dur="5s" begin="2s" repeatCount="indefinite" />
282289 </circle>
283290 </g>
284291
285292 <!-- Top left panel - User info -->
286293 ${ ! hideTitle ? `
287294 <g transform="translate(40, 40)">
288- <rect width="280" height="120" rx="8" fill="url(#panelGradient)" stroke="#00c8ff" stroke-width="1" opacity="0.8"/>
289- <line x1="0" y1="35" x2="280" y2="35" stroke="#00c8ff" stroke-width="1" opacity="0.3"/>
295+ <rect width="280" height="120" rx="8" fill="url(#panelGradient)" stroke="#00c8ff" stroke-width="1" opacity="0.8" />
296+ <line x1="0" y1="35" x2="280" y2="35" stroke="#00c8ff" stroke-width="1" opacity="0.3" />
290297
291298 <text x="15" y="25" fill="#00c8ff" font-size="14" font-weight="600" letter-spacing="1">${ customTitle } </text>
292299 <text x="15" y="55" fill="#888" font-size="11" font-weight="500">TOTAL CONTRIBUTIONS</text>
@@ -312,8 +319,8 @@ export class CardRenderer {
312319
313320 <!-- Bottom left panel - Activity -->
314321 <g transform="translate(40, ${ height - 160 } )">
315- <rect width="280" height="120" rx="8" fill="url(#panelGradient)" stroke="#00c8ff" stroke-width="1" opacity="0.8"/>
316- <line x1="0" y1="35" x2="280" y2="35" stroke="#00c8ff" stroke-width="1" opacity="0.3"/>
322+ <rect width="280" height="120" rx="8" fill="url(#panelGradient)" stroke="#00c8ff" stroke-width="1" opacity="0.8" />
323+ <line x1="0" y1="35" x2="280" y2="35" stroke="#00c8ff" stroke-width="1" opacity="0.3" />
317324
318325 <text x="15" y="25" fill="#00c8ff" font-size="14" font-weight="600" letter-spacing="1">REPOSITORY ACTIVITY</text>
319326
@@ -327,8 +334,8 @@ export class CardRenderer {
327334
328335 <!-- Bottom right panel - Terminal style data stream -->
329336 <g transform="translate(${ width - 320 } , ${ height - 160 } )">
330- <rect width="280" height="120" rx="8" fill="url(#panelGradient)" stroke="#00c8ff" stroke-width="1" opacity="0.8"/>
331- <line x1="0" y1="35" x2="280" y2="35" stroke="#00c8ff" stroke-width="1" opacity="0.3"/>
337+ <rect width="280" height="120" rx="8" fill="url(#panelGradient)" stroke="#00c8ff" stroke-width="1" opacity="0.8" />
338+ <line x1="0" y1="35" x2="280" y2="35" stroke="#00c8ff" stroke-width="1" opacity="0.3" />
332339
333340 <text x="15" y="25" fill="#00c8ff" font-size="14" font-weight="600" letter-spacing="1">DATA STREAM</text>
334341 <text x="15" y="55" fill="#0f0" font-size="9" opacity="0.8">> Analyzing contribution patterns...</text>
0 commit comments