@@ -27,7 +27,11 @@ import Footer from '../components/Footer.astro';
2727 }
2828 </script >
2929 <style >
30- html { scroll-behavior: smooth; }
30+ html {
31+ scroll-behavior: smooth;
32+ --scroll-hue: 0deg;
33+ filter: hue-rotate(var(--scroll-hue));
34+ }
3135 .parallax-shape { transition: transform 0.2s ease-out; }
3236 body::before {
3337 content: "";
@@ -42,100 +46,6 @@ import Footer from '../components/Footer.astro';
4246 50% { opacity: 0.05; transform: scale(1.2); }
4347 100% { opacity: 0.2; transform: scale(1); }
4448 }
45- :root {
46- --glitch-offset-x: 8px;
47- --glitch-offset-y: -8px;
48- --glitch-skew-before: -5deg;
49- --glitch-skew-middle: -3deg;
50- --glitch-skew-after: 5deg;
51- --glitch-hue-before: 10deg;
52- --glitch-hue-after: -10deg;
53- --glitch-opacity-before: 0.6;
54- --glitch-opacity-after: 0.8;
55- --glitch-stripe-light: 0.1;
56- --glitch-stripe-thickness: 2px;
57- --glitch-stripe-gap: 6px;
58- --glitch-stripe-color: 255,255,255;
59- --glitch-page-hue: 20deg;
60- --glitch-page-contrast: 200%;
61- --glitch-page-brightness: 1.2;
62- }
63- #glitch-overlay {
64- position: fixed;
65- inset: 0;
66- pointer-events: none;
67- z-index: 50;
68- background: repeating-linear-gradient(
69- 45deg,
70- rgba(var(--glitch-stripe-color),var(--glitch-stripe-light,0.1)),
71- rgba(var(--glitch-stripe-color),var(--glitch-stripe-light,0.1)) var(--glitch-stripe-thickness,2px),
72- transparent var(--glitch-stripe-thickness,2px),
73- transparent calc(var(--glitch-stripe-thickness,2px) + var(--glitch-stripe-gap,6px))
74- );
75- opacity: 0;
76- }
77- #glitch-overlay::before,
78- #glitch-overlay::after {
79- content: '';
80- position: absolute;
81- inset: 0;
82- background: inherit;
83- opacity: 0;
84- }
85- #glitch-overlay.animate-glitch::before {
86- animation: glitch-before 0.6s steps(2) forwards;
87- }
88- #glitch-overlay.animate-glitch::after {
89- animation: glitch-after 0.6s steps(2) forwards;
90- }
91- @keyframes glitch-before {
92- 0% { opacity: 0; transform: translate(0); filter: hue-rotate(var(--glitch-hue-before,10deg)); }
93- 20% { opacity: var(--glitch-opacity-before,0.6); transform: translate(var(--glitch-offset-x,-8px), var(--glitch-offset-y,-8px)) skew(var(--glitch-skew-before,-5deg)); }
94- 40% { opacity: calc(var(--glitch-opacity-before,0.6) / 2); transform: translate(calc(-1 * var(--glitch-offset-x,-8px)), calc(-1 * var(--glitch-offset-y,-8px))) skew(var(--glitch-skew-after,3deg)); }
95- 60% { opacity: var(--glitch-opacity-before,0.6); transform: translate(calc(-0.5 * var(--glitch-offset-x,-8px)), calc(0.5 * var(--glitch-offset-y,-8px))) skew(var(--glitch-skew-middle,-3deg)); }
96- 80% { opacity: calc(var(--glitch-opacity-before,0.6) / 2); transform: translate(var(--glitch-offset-x,-8px), calc(-0.5 * var(--glitch-offset-y,-8px))) skew(var(--glitch-skew-last,5deg)); }
97- 100% { opacity: 0; transform: translate(0); }
98- }
99- @keyframes glitch-after {
100- 0% { opacity: 0; transform: translate(0); filter: hue-rotate(var(--glitch-hue-after,-10deg)); }
101- 20% { opacity: var(--glitch-opacity-after,0.8); transform: translate(calc(var(--glitch-offset-x,8px)), calc(var(--glitch-offset-y,8px))) skew(var(--glitch-skew-after,5deg)); }
102- 40% { opacity: calc(var(--glitch-opacity-after,0.8) / 2); transform: translate(calc(-1 * var(--glitch-offset-x,8px)), calc(-1 * var(--glitch-offset-y,8px))) skew(var(--glitch-skew-before,-5deg)); }
103- 60% { opacity: var(--glitch-opacity-after,0.8); transform: translate(calc(0.5 * var(--glitch-offset-x,8px)), calc(-0.5 * var(--glitch-offset-y,8px))) skew(var(--glitch-skew-middle,3deg)); }
104- 80% { opacity: calc(var(--glitch-opacity-after,0.8) / 2); transform: translate(calc(-0.5 * var(--glitch-offset-x,8px)), calc(0.5 * var(--glitch-offset-y,8px))) skew(var(--glitch-skew-last,-3deg)); }
105- 100% { opacity: 0; transform: translate(0); }
106- }
107-
108- html.glitch-shake {
109- filter: hue-rotate(var(--glitch-page-hue)) contrast(var(--glitch-page-contrast)) brightness(var(--glitch-page-brightness));
110- }
111- html.glitch-shake.animate-shake {
112- animation: glitch-shake 0.5s steps(2) forwards;
113- }
114- @keyframes glitch-shake {
115- 0% { transform: translate(0); }
116- 25% { transform: translate(-6px, 6px) skewX(-3deg); }
117- 50% { transform: translate(6px, -6px) skewY(3deg); }
118- 75% { transform: translate(-6px, -6px) skew(-3deg); }
119- 100% { transform: translate(0); }
120- }
121- @keyframes pixelate {
122- 0% { filter: none; transform: scale(1); image-rendering: auto; }
123- 50% { filter: blur(2px); transform: scale(0.9); image-rendering: pixelated; }
124- 100% { filter: none; transform: scale(1); image-rendering: auto; }
125- }
126- .animate-pixelate { animation: pixelate 0.8s steps(2) forwards; }
127- /* matrix rain canvas overlay */
128- #matrix-canvas {
129- position: fixed;
130- top: 0;
131- left: 0;
132- width: 100%;
133- height: 100%;
134- pointer-events: none;
135- z-index: 60;
136- opacity: 0;
137- transition: opacity 0.3s ease-out;
138- }
13949 </style >
14050 </head >
14151 <body class =" bg-background text-foreground font-sans" >
@@ -144,7 +54,6 @@ import Footer from '../components/Footer.astro';
14454 <slot />
14555 </main >
14656 <Footer />
147- <div id =" glitch-overlay" ></div >
14857 <script >
14958 const htmlEl = document.documentElement;
15059 const toggle = document.getElementById("theme-toggle");
@@ -186,31 +95,6 @@ import Footer from '../components/Footer.astro';
18695 gyroscope: false
18796 });
18897 }
189- function blockDropEffect(duration = 800) {
190- const count = 60;
191- const blocks = [];
192- for (let i = 0; i < count; i++) {
193- const block = document.createElement('div');
194- const size = Math.floor(Math.random() * 40 + 10);
195- block.style.position = 'fixed';
196- block.style.width = block.style.height = size + 'px';
197- block.style.left = Math.random() * window.innerWidth + 'px';
198- block.style.top = Math.random() * window.innerHeight + 'px';
199- block.style.backgroundColor = `rgba(${Math.floor(Math.random()*256)},${Math.floor(Math.random()*256)},${Math.floor(Math.random()*256)},0.6)`;
200- block.style.zIndex = '70';
201- block.style.pointerEvents = 'none';
202- block.style.transition = `all ${duration}ms ease-out`;
203- document.body.appendChild(block);
204- blocks.push(block);
205- setTimeout(() => {
206- block.style.top = window.innerHeight + 'px';
207- block.style.opacity = '0';
208- }, 50);
209- }
210- setTimeout(() => {
211- blocks.forEach(b => b.remove());
212- }, duration + 500);
213- }
21498
21599 // Initialize particles background
216100 const particlesContainer = document.getElementById('tsparticles');
@@ -268,85 +152,14 @@ import Footer from '../components/Footer.astro';
268152 }, 150 * i + 200);
269153 });
270154
155+ // change page hue based on scroll position
156+ window.addEventListener('scroll', () => {
157+ const scrollFraction = window.scrollY / (document.body.scrollHeight - window.innerHeight);
158+ const hue = scrollFraction * 360;
159+ document.documentElement.style.setProperty('--scroll-hue', `${hue}deg`);
160+ });
161+
271162
272- const glitchEl = document.getElementById('glitch-overlay');
273- const matrixEl = document.createElement('canvas');
274- matrixEl.id = 'matrix-canvas';
275- document.body.append(matrixEl);
276- const mCtx = matrixEl.getContext('2d');
277- function matrixEffect(duration = 800) {
278- matrixEl.width = window.innerWidth;
279- matrixEl.height = window.innerHeight;
280- const cols = Math.floor(matrixEl.width / 20) + 1;
281- const drops = Array(cols).fill(0);
282- matrixEl.style.opacity = '1';
283- const draw = () => {
284- mCtx.fillStyle = 'rgba(0,0,0,0.05)';
285- mCtx.fillRect(0, 0, matrixEl.width, matrixEl.height);
286- mCtx.fillStyle = '#0f0';
287- mCtx.font = '15px monospace';
288- drops.forEach((y, i) => {
289- const text = String.fromCharCode(0x30A0 + Math.random() * 96);
290- mCtx.fillText(text, i * 20, y * 20);
291- drops[i] = y * 20 > matrixEl.height || Math.random() > 0.975 ? 0 : y + 1;
292- });
293- };
294- const timer = setInterval(draw, 50);
295- setTimeout(() => {
296- clearInterval(timer);
297- matrixEl.style.opacity = '0';
298- mCtx.clearRect(0, 0, matrixEl.width, matrixEl.height);
299- }, duration);
300- }
301- (function glitchLoop() {
302- const timeout = Math.random() * 6000 + 2000;
303- setTimeout(() => {
304-
305- const root = document.documentElement;
306- root.style.setProperty('--glitch-offset-x', `${(Math.random()*2-1)*10}px`);
307- root.style.setProperty('--glitch-offset-y', `${(Math.random()*2-1)*10}px`);
308- root.style.setProperty('--glitch-skew-before', `${(Math.random()*10-5).toFixed(2)}deg`);
309- root.style.setProperty('--glitch-skew-middle', `${(Math.random()*10-5).toFixed(2)}deg`);
310- root.style.setProperty('--glitch-skew-after', `${(Math.random()*10-5).toFixed(2)}deg`);
311- root.style.setProperty('--glitch-hue-before', `${(Math.random()*40-20).toFixed(2)}deg`);
312- root.style.setProperty('--glitch-hue-after', `${(Math.random()*40-20).toFixed(2)}deg`);
313- root.style.setProperty('--glitch-opacity-before', `${(Math.random()*0.5+0.3).toFixed(2)}`);
314- root.style.setProperty('--glitch-opacity-after', `${(Math.random()*0.5+0.3).toFixed(2)}`);
315-
316- root.style.setProperty('--glitch-page-hue', `${(Math.random()*360).toFixed(1)}deg`);
317- root.style.setProperty('--glitch-page-contrast', `${(Math.random()*150+150).toFixed(0)}%`);
318- root.style.setProperty('--glitch-page-brightness', `${(Math.random()*0.7+0.8).toFixed(2)}`);
319- root.style.setProperty(
320- '--glitch-stripe-color',
321- `${Math.floor(Math.random()*256)},${Math.floor(Math.random()*256)},${Math.floor(Math.random()*256)}`
322- );
323- root.style.setProperty('--glitch-stripe-light', `${(Math.random()*0.4+0.1).toFixed(2)}`);
324- root.style.setProperty('--glitch-stripe-thickness', `${Math.floor(Math.random()*6+1)}px`);
325- root.style.setProperty('--glitch-stripe-gap', `${Math.floor(Math.random()*12+4)}px`);
326-
327- // trigger shake + stripe glitch
328- root.classList.add('glitch-shake', 'animate-shake');
329- document.documentElement.addEventListener('animationend', () => {
330- document.documentElement.classList.remove('animate-shake');
331- }, { once: true });
332- // random additional effect: matrix rain, pixelate, or block drop
333- const extra = Math.random();
334- if (extra < 0.33) {
335- matrixEffect(1000);
336- } else if (extra < 0.66) {
337- root.classList.add('animate-pixelate');
338- root.addEventListener('animationend', () => root.classList.remove('animate-pixelate'), { once: true });
339- } else {
340- blockDropEffect(1000);
341- }
342- glitchEl.classList.add('animate-glitch');
343- glitchEl.addEventListener('animationend', () => {
344- glitchEl.classList.remove('animate-glitch');
345- document.documentElement.classList.remove('glitch-shake');
346- }, { once: true });
347- glitchLoop();
348- }, timeout);
349- })();
350163 });
351164 </script >
352165 </body >
0 commit comments