Skip to content

Commit c50f768

Browse files
committed
easter egg effect added
1 parent 4869549 commit c50f768

5 files changed

Lines changed: 182 additions & 61 deletions

File tree

src/app.css

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -139,109 +139,114 @@ main {
139139
opacity: 1;
140140
transform: translateY(0);
141141
}
142-
/* --- Glitch Effect --- */
142+
143+
/* --- Corrected Glitch Effect --- */
144+
143145
.glitch {
144146
position: relative;
145-
/* Use Catppuccin colors for a cohesive theme */
147+
/* Using Catppuccin colors for better theme integration */
146148
color: #cba6f7; /* Mauve */
147-
/* Animation: name duration timing-function delay iteration-count direction fill-mode */
148-
animation: glitch-skew 1s infinite linear alternate-reverse;
149149
}
150150

151+
/* Common styles for the glitch layers */
151152
.glitch::before,
152153
.glitch::after {
153-
content: attr(data-text);
154+
content: attr(data-text); /* Use the text from the HTML element */
154155
position: absolute;
155156
top: 0;
156157
left: 0;
157158
width: 100%;
158159
height: 100%;
159-
background: #1e1e2e; /* Base color to prevent transparency issues */
160+
overflow: hidden;
161+
background: #1e1e2e; /* Base color */
160162
}
161163

162-
/* Red channel glitch */
164+
/* Red channel effect */
163165
.glitch::before {
164-
left: 2px;
166+
left: 3px;
165167
text-shadow: -2px 0 #f38ba8; /* Red */
166-
clip-path: inset(50% 0 51% 0);
167-
animation: glitch-anim-1 2s infinite linear alternate-reverse;
168+
/* This animation uses steps for a sharp, random-feeling clip effect */
169+
animation: glitch-animation-1 2s linear infinite reverse alternate;
168170
}
169171

170-
/* Blue channel glitch */
172+
/* Blue channel effect */
171173
.glitch::after {
172-
left: -2px;
174+
left: -3px;
173175
text-shadow: -2px 0 #89b4fa; /* Blue */
174-
clip-path: inset(0% 0 95% 0);
175-
animation: glitch-anim-2 3s infinite linear alternate-reverse;
176+
animation: glitch-animation-2 2s linear infinite reverse alternate;
176177
}
177178

178179
/* --- Keyframes --- */
180+
/* Manually creating steps to simulate the Sass @for loop and random() function */
179181

180-
/* Main element's skewing animation */
181-
@keyframes glitch-skew {
182+
@keyframes glitch-animation-1 {
182183
0% {
183-
transform: skew(0deg);
184-
}
185-
5% {
186-
transform: skew(1deg);
184+
clip-path: inset(45px 0 105px 0);
187185
}
188186
10% {
189-
transform: skew(1deg);
190-
}
191-
15% {
192-
transform: skew(-1deg);
187+
clip-path: inset(10px 0 90px 0);
193188
}
194189
20% {
195-
transform: skew(-1deg);
196-
}
197-
25% {
198-
transform: skew(0deg);
199-
}
200-
100% {
201-
transform: skew(0deg);
202-
}
203-
}
204-
205-
/* Animation for the red channel pseudo-element */
206-
@keyframes glitch-anim-1 {
207-
0% {
208-
clip-path: inset(50% 0 51% 0);
190+
clip-path: inset(130px 0 5px 0);
209191
}
210-
20% {
211-
clip-path: inset(10% 0 85% 0);
192+
30% {
193+
clip-path: inset(50px 0 80px 0);
212194
}
213195
40% {
214-
clip-path: inset(80% 0 10% 0);
196+
clip-path: inset(70px 0 15px 0);
197+
}
198+
50% {
199+
clip-path: inset(140px 0 10px 0);
215200
}
216201
60% {
217-
clip-path: inset(40% 0 45% 0);
202+
clip-path: inset(20px 0 125px 0);
203+
}
204+
70% {
205+
clip-path: inset(100px 0 30px 0);
218206
}
219207
80% {
220-
clip-path: inset(90% 0 5% 0);
208+
clip-path: inset(60px 0 40px 0);
209+
}
210+
90% {
211+
clip-path: inset(120px 0 25px 0);
221212
}
222213
100% {
223-
clip-path: inset(25% 0 70% 0);
214+
clip-path: inset(5px 0 110px 0);
224215
}
225216
}
226217

227-
/* Animation for the blue channel pseudo-element */
228-
@keyframes glitch-anim-2 {
218+
@keyframes glitch-animation-2 {
229219
0% {
230-
clip-path: inset(0% 0 95% 0);
220+
clip-path: inset(120px 0 15px 0);
221+
}
222+
10% {
223+
clip-path: inset(40px 0 80px 0);
231224
}
232225
20% {
233-
clip-path: inset(60% 0 35% 0);
226+
clip-path: inset(5px 0 130px 0);
227+
}
228+
30% {
229+
clip-path: inset(90px 0 20px 0);
234230
}
235231
40% {
236-
clip-path: inset(20% 0 75% 0);
232+
clip-path: inset(10px 0 100px 0);
233+
}
234+
50% {
235+
clip-path: inset(115px 0 5px 0);
237236
}
238237
60% {
239-
clip-path: inset(95% 0 2% 0);
238+
clip-path: inset(30px 0 70px 0);
239+
}
240+
70% {
241+
clip-path: inset(145px 0 10px 0);
240242
}
241243
80% {
242-
clip-path: inset(15% 0 80% 0);
244+
clip-path: inset(25px 0 95px 0);
245+
}
246+
90% {
247+
clip-path: inset(105px 0 35px 0);
243248
}
244249
100% {
245-
clip-path: inset(70% 0 25% 0);
250+
clip-path: inset(15px 0 120px 0);
246251
}
247252
}

src/app.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<meta charset="utf-8" />
55
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1" />
7-
<link href="/app.css" rel="stylesheet" />
87
%sveltekit.head%
98
</head>
109
<body data-sveltekit-preload-data="hover" class="bg-ctp-base text-ctp-text">

src/lib/components/Footer.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
>
2929
</a>
3030
<a
31-
href="https://www.linkedin.com/in/kylee-benisty/"
31+
href="https://www.linkedin.com/in/rekylee/"
3232
target="_blank"
3333
class="text-ctp-text transition-colors hover:text-ctp-green"
3434
aria-label="LinkedIn"
@@ -53,7 +53,7 @@
5353
>
5454
</a>
5555
<a
56-
href="mailto:kylee.benisty@gmail.com"
56+
href="mailto:ido5490@gmail.com"
5757
class="text-ctp-text transition-colors hover:text-ctp-green"
5858
aria-label="Email"
5959
>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<script lang="ts">
2+
export let href: string | null = null;
3+
export let text: string;
4+
export let size:
5+
| "sm"
6+
| "base"
7+
| "lg"
8+
| "xl"
9+
| "2xl"
10+
| "3xl"
11+
| "4xl"
12+
| "5xl" = "3xl";
13+
export let color: "mauve" | "pink" | "green" | "sky" | "red" = "mauve";
14+
export let loopDelay: number = 2000;
15+
// New prop to control the reveal animation order
16+
export let revealOrder: "random" | "linear" | "reverse" = "random";
17+
18+
// --- Class Mapping for Tailwind ---
19+
const sizeClasses = {
20+
sm: "text-sm",
21+
base: "text-base",
22+
lg: "text-lg",
23+
xl: "text-xl",
24+
"2xl": "text-2xl",
25+
"3xl": "text-3xl",
26+
"4xl": "text-4xl",
27+
"5xl": "text-5xl",
28+
};
29+
const colorClasses = {
30+
mauve: "text-ctp-mauve",
31+
pink: "text-ctp-pink",
32+
green: "text-ctp-green",
33+
sky: "text-ctp-sky",
34+
red: "text-ctp-red",
35+
};
36+
37+
$: finalClasses = `font-mono font-bold ${sizeClasses[size] || sizeClasses["3xl"]} ${colorClasses[color] || colorClasses["mauve"]} cursor-pointer focus:outline-none`;
38+
39+
// --- Scramble Animation Logic ---
40+
let displayedText = text;
41+
const chars = "!<>-_\\/[]{}—=+*^?#";
42+
let scrambleIntervalId: ReturnType<typeof setInterval> | null = null;
43+
let loopTimeoutId: ReturnType<typeof setTimeout> | null = null;
44+
45+
const scramble = () => {
46+
if (scrambleIntervalId) clearInterval(scrambleIntervalId);
47+
48+
// --- THE FIX: Generate the reveal order based on the new prop ---
49+
let indices = text.split("").map((_, i) => i);
50+
if (revealOrder === "random") {
51+
// Shuffle for random order
52+
for (let i = indices.length - 1; i > 0; i--) {
53+
const j = Math.floor(Math.random() * (i + 1));
54+
[indices[i], indices[j]] = [indices[j], indices[i]];
55+
}
56+
} else if (revealOrder === "reverse") {
57+
// Reverse for right-to-left order
58+
indices.reverse();
59+
}
60+
// For 'linear', we just use the default sequential array.
61+
62+
const revealed = new Set<number>();
63+
let step = 0;
64+
scrambleIntervalId = setInterval(() => {
65+
const indexToReveal = indices[step];
66+
if (indexToReveal !== undefined) {
67+
revealed.add(indexToReveal);
68+
}
69+
70+
displayedText = text
71+
.split("")
72+
.map((_letter, index) => {
73+
if (revealed.has(index)) return text[index];
74+
return chars[Math.floor(Math.random() * chars.length)];
75+
})
76+
.join("");
77+
78+
step++;
79+
if (step >= text.length) {
80+
clearInterval(
81+
scrambleIntervalId as ReturnType<typeof setInterval>,
82+
);
83+
displayedText = text;
84+
loopTimeoutId = setTimeout(scramble, loopDelay);
85+
}
86+
}, 40);
87+
};
88+
89+
const stopScramble = () => {
90+
if (scrambleIntervalId) clearInterval(scrambleIntervalId);
91+
if (loopTimeoutId) clearTimeout(loopTimeoutId);
92+
scrambleIntervalId = null;
93+
loopTimeoutId = null;
94+
displayedText = text;
95+
};
96+
97+
// --- Determine element type and attributes ---
98+
$: tag = href ? "a" : "span";
99+
$: attrs = href ? { href } : { role: "button", tabindex: 0 };
100+
</script>
101+
102+
<svelte:element
103+
this={tag}
104+
class={finalClasses}
105+
{...attrs}
106+
on:focus={scramble}
107+
on:mouseenter={scramble}
108+
on:blur={stopScramble}
109+
on:mouseleave={stopScramble}
110+
on:keydown={(e) => {
111+
if (!href && (e.key === "Enter" || e.key === " ")) scramble();
112+
}}
113+
>
114+
{displayedText}
115+
</svelte:element>

src/lib/components/Header.svelte

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import Nav from "$lib/components/Nav.svelte";
33
import ThemeSwitch from "$lib/components/ThemeSwitch.svelte";
44
import { t, language } from "$lib/stores/language";
5+
import GlitchText from "./GlitchText.svelte";
56
</script>
67

78
<header
@@ -14,12 +15,13 @@
1415
alt="Kylee's Logo"
1516
class="h-18 mr-4 inline-block"
1617
/>
17-
<span
18-
class="glitch text-3xl font-bold text-ctp-pink"
19-
data-text={$t("name")}
20-
>
21-
{$t("name")}
22-
</span>
18+
<GlitchText
19+
text={$t("name")}
20+
loopDelay={1500}
21+
revealOrder="random"
22+
size="3xl"
23+
color="mauve"
24+
/>
2325
</div>
2426
<Nav />
2527
<div class="flex items-center space-x-4">

0 commit comments

Comments
 (0)