Skip to content

Commit 33988ee

Browse files
greyliclaude
andcommitted
Add star button
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 49101f0 commit 33988ee

3 files changed

Lines changed: 265 additions & 2 deletions

File tree

readme/script.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,96 @@ function initializePage() {
352352
updateOutlineLanguage();
353353
}
354354

355+
// Star Tornado Animation
356+
function createStarTornado() {
357+
// Create container for stars
358+
const container = document.createElement('div');
359+
container.className = 'star-tornado-container';
360+
document.body.appendChild(container);
361+
362+
// Star symbols array for variety
363+
const starSymbols = ['⭐', '✨', '🌟', '💫', '⭐', '✨'];
364+
365+
// Create multiple star particles
366+
const numStars = 80;
367+
368+
for (let i = 0; i < numStars; i++) {
369+
const star = document.createElement('div');
370+
star.className = 'star-particle';
371+
star.textContent = starSymbols[Math.floor(Math.random() * starSymbols.length)];
372+
373+
// Random starting position across the screen bottom
374+
const startX = Math.random() * window.innerWidth;
375+
const startY = window.innerHeight + 50; // Start below the screen
376+
377+
star.style.left = startX + 'px';
378+
star.style.top = startY + 'px';
379+
380+
// Random size variation - much bigger
381+
const size = 40 + Math.random() * 60;
382+
star.style.fontSize = size + 'px';
383+
384+
// Choose random animation from 5 different float patterns
385+
const animations = ['starFloat1', 'starFloat2', 'starFloat3', 'starFloat4', 'starFloat5'];
386+
const animation = animations[Math.floor(Math.random() * animations.length)];
387+
388+
// Random duration between 2.5s and 5s
389+
const duration = 2.5 + Math.random() * 2.5;
390+
391+
// Random delay up to 1.5s
392+
const delay = Math.random() * 1.5;
393+
394+
star.style.animation = `${animation} ${duration}s ease-out ${delay}s forwards`;
395+
396+
// Random rotation for variety
397+
const rotation = Math.random() * 360;
398+
star.style.transform = `rotate(${rotation}deg)`;
399+
400+
container.appendChild(star);
401+
}
402+
403+
// Add some extra sparkles that appear later
404+
setTimeout(() => {
405+
for (let i = 0; i < 50; i++) {
406+
const sparkle = document.createElement('div');
407+
sparkle.className = 'star-particle';
408+
sparkle.textContent = '✨';
409+
410+
const x = Math.random() * window.innerWidth;
411+
const y = window.innerHeight + 50; // Start below screen like main stars
412+
413+
sparkle.style.left = x + 'px';
414+
sparkle.style.top = y + 'px';
415+
sparkle.style.fontSize = (35 + Math.random() * 45) + 'px';
416+
417+
// Use random animation for sparkles too
418+
const sparkleAnimations = ['starFloat1', 'starFloat2', 'starFloat3', 'starFloat4', 'starFloat5'];
419+
const sparkleAnimation = sparkleAnimations[Math.floor(Math.random() * sparkleAnimations.length)];
420+
const sparkleDuration = 2.5 + Math.random() * 2;
421+
422+
sparkle.style.animation = `${sparkleAnimation} ${sparkleDuration}s ease-out forwards`;
423+
424+
container.appendChild(sparkle);
425+
}
426+
}, 500);
427+
428+
// Clean up after animation completes
429+
setTimeout(() => {
430+
if (container && container.parentNode) {
431+
container.parentNode.removeChild(container);
432+
}
433+
}, 4000);
434+
435+
// Add button press effect
436+
const starButton = document.querySelector('.star-button');
437+
if (starButton) {
438+
starButton.style.transform = 'scale(0.9)';
439+
setTimeout(() => {
440+
starButton.style.transform = '';
441+
}, 150);
442+
}
443+
}
444+
355445
// Smooth scrolling for anchor links
356446
document.addEventListener('DOMContentLoaded', function() {
357447
// Initialize page with detected language

readme/style.css

Lines changed: 172 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ body {
8383
gap: 8px;
8484
}
8585

86-
.language-switch, .theme-toggle {
86+
.star-button, .language-switch, .theme-toggle {
8787
background: var(--bg-tertiary);
8888
border: 1px solid var(--border-primary);
8989
color: var(--text-primary);
@@ -94,11 +94,21 @@ body {
9494
transition: all 0.2s;
9595
}
9696

97-
.language-switch:hover, .theme-toggle:hover {
97+
.star-button:hover, .language-switch:hover, .theme-toggle:hover {
9898
background: var(--border-primary);
9999
border-color: var(--border-secondary);
100100
}
101101

102+
.star-button {
103+
display: flex;
104+
align-items: center;
105+
gap: 4px;
106+
}
107+
108+
.star-button:hover {
109+
transform: scale(1.1);
110+
}
111+
102112
.theme-toggle {
103113
display: flex;
104114
align-items: center;
@@ -577,6 +587,166 @@ a:hover {
577587
transform: translateY(-1px);
578588
}
579589

590+
/* Star Tornado Animation */
591+
.star-tornado-container {
592+
position: fixed;
593+
top: 0;
594+
left: 0;
595+
width: 100vw;
596+
height: 100vh;
597+
pointer-events: none;
598+
z-index: 9999;
599+
}
600+
601+
.star-particle {
602+
position: absolute;
603+
font-size: 16px;
604+
color: #ffd700;
605+
pointer-events: none;
606+
z-index: 10000;
607+
}
608+
609+
@keyframes starTornado {
610+
0% {
611+
transform: rotate(0deg) translateX(0px) scale(0);
612+
opacity: 0;
613+
}
614+
10% {
615+
opacity: 1;
616+
transform: rotate(36deg) translateX(50px) scale(1);
617+
}
618+
50% {
619+
opacity: 1;
620+
transform: rotate(180deg) translateX(150px) scale(1.2);
621+
}
622+
90% {
623+
opacity: 1;
624+
transform: rotate(324deg) translateX(250px) scale(0.8);
625+
}
626+
100% {
627+
opacity: 0;
628+
transform: rotate(360deg) translateX(300px) scale(0);
629+
}
630+
}
631+
632+
@keyframes starSpiral {
633+
0% {
634+
transform: rotate(0deg) translateX(0px) translateY(0px) scale(0);
635+
opacity: 0;
636+
}
637+
10% {
638+
opacity: 1;
639+
transform: rotate(72deg) translateX(80px) translateY(-20px) scale(1);
640+
}
641+
30% {
642+
opacity: 1;
643+
transform: rotate(216deg) translateX(160px) translateY(-60px) scale(1.3);
644+
}
645+
70% {
646+
opacity: 1;
647+
transform: rotate(504deg) translateX(240px) translateY(-120px) scale(1);
648+
}
649+
100% {
650+
opacity: 0;
651+
transform: rotate(720deg) translateX(320px) translateY(-200px) scale(0);
652+
}
653+
}
654+
655+
@keyframes starFloat1 {
656+
0% {
657+
transform: translateY(0px) translateX(0px) scale(0) rotate(0deg);
658+
opacity: 0;
659+
}
660+
15% {
661+
opacity: 1;
662+
transform: translateY(-80px) translateX(20px) scale(1) rotate(45deg);
663+
}
664+
60% {
665+
opacity: 1;
666+
transform: translateY(-400px) translateX(-30px) scale(1.3) rotate(180deg);
667+
}
668+
100% {
669+
opacity: 0;
670+
transform: translateY(-650px) translateX(50px) scale(0) rotate(360deg);
671+
}
672+
}
673+
674+
@keyframes starFloat2 {
675+
0% {
676+
transform: translateY(0px) translateX(0px) scale(0) rotate(0deg);
677+
opacity: 0;
678+
}
679+
20% {
680+
opacity: 1;
681+
transform: translateY(-100px) translateX(-40px) scale(1.1) rotate(90deg);
682+
}
683+
70% {
684+
opacity: 1;
685+
transform: translateY(-500px) translateX(60px) scale(1.4) rotate(270deg);
686+
}
687+
100% {
688+
opacity: 0;
689+
transform: translateY(-800px) translateX(-20px) scale(0) rotate(450deg);
690+
}
691+
}
692+
693+
@keyframes starFloat3 {
694+
0% {
695+
transform: translateY(0px) translateX(0px) scale(0) rotate(0deg);
696+
opacity: 0;
697+
}
698+
10% {
699+
opacity: 1;
700+
transform: translateY(-60px) translateX(15px) scale(0.9) rotate(30deg);
701+
}
702+
40% {
703+
opacity: 1;
704+
transform: translateY(-250px) translateX(-45px) scale(1.2) rotate(120deg);
705+
}
706+
100% {
707+
opacity: 0;
708+
transform: translateY(-450px) translateX(35px) scale(0) rotate(240deg);
709+
}
710+
}
711+
712+
@keyframes starFloat4 {
713+
0% {
714+
transform: translateY(0px) translateX(0px) scale(0) rotate(0deg);
715+
opacity: 0;
716+
}
717+
25% {
718+
opacity: 1;
719+
transform: translateY(-120px) translateX(-25px) scale(1.3) rotate(60deg);
720+
}
721+
80% {
722+
opacity: 1;
723+
transform: translateY(-600px) translateX(80px) scale(1.5) rotate(300deg);
724+
}
725+
100% {
726+
opacity: 0;
727+
transform: translateY(-900px) translateX(-60px) scale(0) rotate(480deg);
728+
}
729+
}
730+
731+
@keyframes starFloat5 {
732+
0% {
733+
transform: translateY(0px) translateX(0px) scale(0) rotate(0deg);
734+
opacity: 0;
735+
}
736+
12% {
737+
opacity: 1;
738+
transform: translateY(-70px) translateX(35px) scale(1) rotate(75deg);
739+
}
740+
55% {
741+
opacity: 1;
742+
transform: translateY(-350px) translateX(-55px) scale(1.1) rotate(200deg);
743+
}
744+
100% {
745+
opacity: 0;
746+
transform: translateY(-550px) translateX(25px) scale(0) rotate(315deg);
747+
}
748+
}
749+
580750
/* Responsive */
581751
@media (max-width: 600px) {
582752
.readme-header {

templates/base.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
</a>
1919
</div>
2020
<div class="header-controls">
21+
<button class="star-button" onclick="createStarTornado()">
22+
<span></span>
23+
</button>
2124
<button class="theme-toggle" onclick="toggleTheme()">
2225
<span id="theme-icon">{{ ui_text.en.theme_toggle }}</span>
2326
</button>

0 commit comments

Comments
 (0)