@@ -156,11 +156,26 @@ function renderStyle(
156156 @import url('https://fonts.googleapis.com/css2?family=Fira+Code&family=JetBrains+Mono&family=Roboto&family=Syncopate:wght@400;700&family=Space+Grotesk:wght@400;500;600;700&display=swap');
157157 ${ googleFontsImport }
158158 ${ TOWER_ANIMATION_CSS }
159+ .scan-line {
160+ animation: scan-sweep var(--scan-speed, 8s) linear infinite;
161+ transform-box: fill-box;
162+ transform-origin: center;
163+ }
164+ @keyframes scan-sweep {
165+ from { transform: translateY(var(--scan-start, ${ fs ( 20 ) } px)); }
166+ to { transform: translateY(var(--scan-end, ${ fs ( 260 ) } px)); }
167+ }
159168 .title { font-family: ${ selectedFont || '"Syncopate", sans-serif' } ; fill: ${ text } ; font-size: ${ fs ( 18 ) } px; letter-spacing: ${ fs ( 6 ) } px; font-weight: 400; opacity: 0.8; }
160169 .stats { font-family: ${ statsFont } ; fill: ${ text } ; font-size: ${ fs ( 42 ) } px; font-weight: 500; letter-spacing: 0; }
161170 .total-val { font-family: ${ statsFont } ; fill: ${ accent } ; font-size: ${ fs ( 24 ) } px; font-weight: 500; }
162171 .label { font-family: "Roboto", sans-serif; fill: ${ accent } ; font-size: ${ fs ( 11 ) } px; font-weight: 400; letter-spacing: ${ fs ( 2 ) } px; opacity: 0.7; }
163- @media (prefers-reduced-motion: reduce) { .heat-particles { display: none; } }
172+ @media (prefers-reduced-motion: reduce) {
173+ .heat-particles { display: none; }
174+ .scan-line {
175+ animation: none !important;
176+ transform: translateY(var(--scan-start, ${ fs ( 20 ) } px)) !important;
177+ }
178+ }
164179 </style>` ;
165180}
166181
@@ -198,9 +213,15 @@ function renderFooter(
198213 return `
199214 ${ ! params . hide_stats ? renderStatsSection ( stats , labels , s , params ) : '' }
200215 ${ ! params . hide_title ? `<text x="${ s ( 300 ) } " y="${ s ( 50 ) } " text-anchor="middle" class="title">${ truncateUsername ( safeUser ) . toUpperCase ( ) } </text>` : '' }
201- <rect x="${ s ( 100 ) } " y="${ s ( 60 ) } " width="${ s ( 400 ) } " height="${ sf } " fill="${ accent } " fill-opacity="0.3">
202- <animate attributeName="y" values="${ s ( 80 ) } ;${ s ( 320 ) } ;${ s ( 80 ) } " dur="${ params . speed || '8s' } " repeatCount="indefinite" />
203- </rect>` ;
216+ <rect
217+ x="${ s ( 100 ) } "
218+ y="${ s ( 60 ) } "
219+ width="${ s ( 400 ) } "
220+ height="${ sf } "
221+ class="cp-accent-fill scan-line"
222+ fill-opacity="0.3"
223+ style="--scan-speed: ${ params . speed || '8s' } ; --scan-start: ${ s ( 20 ) } px; --scan-end: ${ s ( 260 ) } px;"
224+ />` ;
204225}
205226
206227// ββ Main static-theme renderer ββββββββββββββββββββββββββββββββββββββββββββ
@@ -319,12 +340,27 @@ function generateAutoThemeSVG(
319340 @media (prefers-color-scheme: dark) { :root { --cp-bg: #${ dark . bg } ; --cp-text: #${ dark . text } ; --cp-accent: #${ dark . accent } ; } }
320341 .cp-bg-fill { fill: var(--cp-bg); } .cp-text-fill { fill: var(--cp-text); color: var(--cp-text); } .cp-accent-fill { fill: var(--cp-accent); color: var(--cp-accent); }
321342 ${ TOWER_ANIMATION_CSS }
343+ .scan-line {
344+ animation: scan-sweep var(--scan-speed, 8s) linear infinite;
345+ transform-box: fill-box;
346+ transform-origin: center;
347+ }
348+ @keyframes scan-sweep {
349+ from { transform: translateY(var(--scan-start, ${ s ( 20 ) } px)); }
350+ to { transform: translateY(var(--scan-end, ${ s ( 260 ) } px)); }
351+ }
322352 .title { font-family: ${ selectedFont || '"Syncopate", sans-serif' } ; fill: var(--cp-text); font-size: ${ fs ( 18 ) } px; letter-spacing: ${ fs ( 6 ) } px; font-weight: 400; opacity: 0.8; }
323353 .stats { font-family: ${ statsFont } ; fill: var(--cp-text); font-size: ${ fs ( 42 ) } px; font-weight: 500; letter-spacing: 0; }
324354 .total-val { font-family: ${ statsFont } ; fill: var(--cp-accent); font-size: ${ fs ( 24 ) } px; font-weight: 500; }
325355 .label { font-family: "Roboto", sans-serif; fill: var(--cp-accent); font-size: ${ fs ( 11 ) } px; font-weight: 400; letter-spacing: ${ fs ( 2 ) } px; opacity: 0.7; }
326356
327- @media (prefers-reduced-motion: reduce) { .heat-particles { display: none; } }
357+ @media (prefers-reduced-motion: reduce) {
358+ .heat-particles { display: none; }
359+ .scan-line {
360+ animation: none !important;
361+ transform: translateY(var(--scan-start, ${ s ( 20 ) } px)) !important;
362+ }
363+ }
328364 </style>
329365
330366 <rect width="${ W } " height="${ H } " rx="${ radius } " ${ params . hideBackground ? 'fill="transparent"' : 'class="cp-bg-fill"' } />
338374 : ''
339375}
340376
341- <rect x="${ s ( 100 ) } " y="${ s ( 60 ) } " width="${ s ( 400 ) } " height="${ sf } " class="cp-accent-fill" fill-opacity="0.3">
342- <animate attributeName="y" values="${ s ( 80 ) } ;${ s ( 320 ) } ;${ s ( 80 ) } " dur="${ params . speed || '8s' } " repeatCount="indefinite" />
343- </rect>
377+ <rect
378+ x="${ s ( 100 ) } "
379+ y="${ s ( 60 ) } "
380+ width="${ s ( 400 ) } "
381+ height="${ sf } "
382+ class="cp-accent-fill scan-line"
383+ fill-opacity="0.3"
384+ style="--scan-speed: ${ params . speed || '8s' } ; --scan-start: ${ s ( 20 ) } px; --scan-end: ${ s ( 260 ) } px;"
385+ />
344386</svg>
345387` ;
346388}
@@ -677,8 +719,16 @@ export function generateNotFoundSVG(
677719 .label { font-family: "Roboto", sans-serif; fill: ${ accent } ; font-size: 11px; letter-spacing: 2px; opacity: 0.4; }
678720 .stats { font-family: "Space Grotesk", sans-serif; fill: ${ text } ; font-size: 42px; font-weight: 500; opacity: 0.2; }
679721 .ghost-pulse { animation: gp 2.6s ease-in-out infinite; }
722+ .scan-line { animation: scan-sweep var(--scan-speed, 8s) linear infinite; }
680723 @keyframes gp { 0%,100%{opacity:.55} 50%{opacity:1} }
681- @media (prefers-reduced-motion: reduce) { .ghost-pulse { animation: none; } }
724+ @keyframes scan-sweep { from { transform: translateY(20px); } to { transform: translateY(260px); } }
725+ @media (prefers-reduced-motion: reduce) {
726+ .ghost-pulse { animation: none; }
727+ .scan-line {
728+ animation: none !important;
729+ transform: translateY(20px) !important;
730+ }
731+ }
682732 </style>
683733
684734 <!-- Background -->
@@ -693,9 +743,7 @@ export function generateNotFoundSVG(
693743 <rect width="${ SVG_WIDTH } " height="${ SVG_HEIGHT } " rx="${ radius } " fill="url(#ghostFade)"/>
694744
695745 <!-- Radar scan line -->
696- <rect x="100" y="60" width="400" height="1" fill="${ accent } " fill-opacity="0.12">
697- <animate attributeName="y" values="80;320;80" dur="${ speed } " repeatCount="indefinite"/>
698- </rect>
746+ <rect x="100" y="60" width="400" height="1" class="scan-line" fill="${ accent } " fill-opacity="0.12" style="--scan-speed: ${ speed } ;"/>
699747
700748 <text x="300" y="50" text-anchor="middle" class="title">${ safeName } </text>
701749
0 commit comments