Skip to content

Commit a5fa898

Browse files
committed
✨ Optimize starfield and shooting stars animations for improved performance and visual appeal
1 parent e8333d5 commit a5fa898

File tree

1 file changed

+31
-72
lines changed

1 file changed

+31
-72
lines changed

src/card-renderer.ts

Lines changed: 31 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -27,48 +27,35 @@ export class CardRenderer {
2727
return num.toString();
2828
}
2929

30-
// Generate starfield with animations
31-
const stars = Array.from({ length: 100 }, (_, i) => {
32-
const x = Math.random() * width;
33-
const y = Math.random() * height;
34-
const r = Math.random() * 1.5 + 0.5;
35-
const opacity = +(Math.random() * 0.7 + 0.3).toFixed(2);
36-
const opacityLow = +(opacity * 0.3).toFixed(2);
37-
const twinkleDur = (Math.random() * 3 + 2).toFixed(1); // 2-5 seconds
38-
const moveX = (Math.random() * 4 - 2).toFixed(1); // -2 to +2
39-
const moveY = (Math.random() * 4 - 2).toFixed(1); // -2 to +2
40-
const delay = (Math.random() * 3).toFixed(1);
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" />
44-
</circle>`;
30+
// Generate starfield with animations (reduced count for smaller SVG)
31+
const stars = Array.from({ length: 50 }, (_, i) => {
32+
const x = (Math.random() * width).toFixed(0);
33+
const y = (Math.random() * height).toFixed(0);
34+
const r = (Math.random() * 1.5 + 0.5).toFixed(1);
35+
const opacity = (Math.random() * 0.7 + 0.3).toFixed(1);
36+
const opacityLow = (parseFloat(opacity) * 0.3).toFixed(1);
37+
const twinkleDur = (Math.random() * 3 + 2).toFixed(0);
38+
const delay = (Math.random() * 3).toFixed(0);
39+
return `<circle cx="${x}" cy="${y}" r="${r}" fill="#fff" opacity="${opacity}"><animate attributeName="opacity" values="${opacity};${opacityLow};${opacity}" dur="${twinkleDur}s" begin="${delay}s" repeatCount="indefinite"/></circle>`;
4540
}).join('');
4641

47-
// Generate shooting stars
48-
const shootingStars = Array.from({ length: 3 }, (_, i) => {
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);
57-
const delay = (i * 8 + Math.random() * 4).toFixed(1);
58-
return `
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" />
65-
</line>
66-
`;
42+
// Generate shooting stars (simplified)
43+
const shootingStars = Array.from({ length: 2 }, (_, i) => {
44+
const startX = (Math.random() * width).toFixed(0);
45+
const startY = (Math.random() * (height / 2)).toFixed(0);
46+
const endX = (parseFloat(startX) + 250).toFixed(0);
47+
const endY = (parseFloat(startY) + 170).toFixed(0);
48+
const startX2 = (parseFloat(startX) + 30).toFixed(0);
49+
const startY2 = (parseFloat(startY) + 20).toFixed(0);
50+
const endX2 = (parseFloat(endX) + 30).toFixed(0);
51+
const endY2 = (parseFloat(endY) + 20).toFixed(0);
52+
const delay = (i * 10).toString();
53+
return `<line x1="${startX}" y1="${startY}" x2="${startX2}" y2="${startY2}" stroke="url(#shootingStarGradient)" stroke-width="2" opacity="0" stroke-linecap="round"><animate attributeName="x1" values="${startX};${endX}" dur="2s" begin="${delay}s" repeatCount="indefinite"/><animate attributeName="y1" values="${startY};${endY}" dur="2s" begin="${delay}s" repeatCount="indefinite"/><animate attributeName="x2" values="${startX2};${endX2}" dur="2s" begin="${delay}s" repeatCount="indefinite"/><animate attributeName="y2" values="${startY2};${endY2}" dur="2s" begin="${delay}s" repeatCount="indefinite"/><animate attributeName="opacity" values="0;0.8;0" dur="2s" begin="${delay}s" repeatCount="indefinite"/></line>`;
6754
}).join('');
6855

6956
// Generate orbital rings
7057
const orbitRings = [120, 160, 200, 240].map((r, i) =>
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" />`
58+
`<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"/>`
7259
).join('');
7360

7461
// Generate data beams radiating from center
@@ -96,29 +83,10 @@ export class CardRenderer {
9683
// Label position (further out)
9784
const labelX = (centerX + Math.cos(angle) * (beamLength + 60)).toFixed(1);
9885
const labelY = centerY + Math.sin(angle) * (beamLength + 60);
99-
const labelYTop = (labelY - 12).toFixed(1);
100-
const labelYBottom = (labelY + 6).toFixed(1);
101-
102-
return `
103-
<!-- Beam line -->
104-
<line x1="${centerX}" y1="${centerY}" x2="${endX}" y2="${endY}" stroke="url(#beamGradient${i})" stroke-width="2" opacity="0.6" />
105-
106-
<!-- Glow effect beam -->
107-
<line x1="${centerX}" y1="${centerY}" x2="${endX}" y2="${endY}" stroke="rgba(0, 200, 255, 0.3)" stroke-width="6" filter="url(#glow)" />
108-
109-
<!-- Data point -->
110-
<circle cx="${dotX}" cy="${dotY}" r="6" fill="#00c8ff" filter="url(#glow)">
111-
<animate attributeName="r" values="6;8;6" dur="2s" repeatCount="indefinite" />
112-
</circle>
113-
<circle cx="${dotX}" cy="${dotY}" r="12" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.4">
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" />
116-
</circle>
117-
118-
<!-- Stat label -->
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>
121-
`;
86+
const labelYTop = (labelY - 12).toFixed(0);
87+
const labelYBottom = (labelY + 6).toFixed(0);
88+
89+
return `<line x1="${centerX}" y1="${centerY}" x2="${endX}" y2="${endY}" stroke="url(#beamGradient${i})" stroke-width="2" opacity="0.6"/><line x1="${centerX}" y1="${centerY}" x2="${endX}" y2="${endY}" stroke="rgba(0,200,255,0.3)" stroke-width="6" filter="url(#glow)"/><circle cx="${dotX}" cy="${dotY}" r="6" fill="#00c8ff" filter="url(#glow)"><animate attributeName="r" values="6;8;6" dur="2s" repeatCount="indefinite"/></circle><circle cx="${dotX}" cy="${dotY}" r="12" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.4"><animate attributeName="r" values="12;16;12" dur="2s" repeatCount="indefinite"/><animate attributeName="opacity" values="0.4;0.1;0.4" dur="2s" repeatCount="indefinite"/></circle><text x="${labelX}" y="${labelYTop}" text-anchor="middle" fill="#00c8ff" font-size="11" font-weight="600" filter="url(#glow)">${stat.label}</text><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>`;
12290
}).join('');
12391

12492
// Corner info panels
@@ -267,26 +235,17 @@ export class CardRenderer {
267235
<g filter="url(#strongGlow)">
268236
<!-- Avatar image -->
269237
<image href="${stats.avatarUrl}" x="${centerX - 65}" y="${centerY - 65}" width="130" height="130" clip-path="url(#avatarClip)" opacity="0.9" />
270-
238+
271239
<!-- Avatar border and effects -->
272240
<circle cx="${centerX}" cy="${centerY}" r="65" fill="none" stroke="#00c8ff" stroke-width="3" opacity="0.8" />
273241
<circle cx="${centerX}" cy="${centerY}" r="70" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.5" />
274242
<circle cx="${centerX}" cy="${centerY}" r="80" fill="none" stroke="#00c8ff" stroke-width="2" opacity="0.3" />
275243
<circle cx="${centerX}" cy="${centerY}" r="75" fill="none" stroke="#00c8ff" stroke-width="1" opacity="0.4" stroke-dasharray="4,4" />
276244
277245
<!-- Ping animation rings -->
278-
<circle cx="${centerX}" cy="${centerY}" r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0">
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" />
281-
</circle>
282-
<circle cx="${centerX}" cy="${centerY}" r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0">
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" />
285-
</circle>
286-
<circle cx="${centerX}" cy="${centerY}" r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0">
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" />
289-
</circle>
246+
<circle cx="${centerX}" cy="${centerY}" r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0"><animate attributeName="r" values="80;150;220" dur="5s" repeatCount="indefinite"/><animate attributeName="opacity" values="0.7;0.3;0" dur="5s" repeatCount="indefinite"/></circle>
247+
<circle cx="${centerX}" cy="${centerY}" r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0"><animate attributeName="r" values="80;150;220" dur="5s" begin="1s" repeatCount="indefinite"/><animate attributeName="opacity" values="0.7;0.3;0" dur="5s" begin="1s" repeatCount="indefinite"/></circle>
248+
<circle cx="${centerX}" cy="${centerY}" r="80" fill="none" stroke="#00c8ff54" stroke-width="2" opacity="0"><animate attributeName="r" values="80;150;220" dur="5s" begin="2s" repeatCount="indefinite"/><animate attributeName="opacity" values="0.7;0.3;0" dur="5s" begin="2s" repeatCount="indefinite"/></circle>
290249
</g>
291250
292251
<!-- Top left panel - User info -->

0 commit comments

Comments
 (0)