create-neon-flux 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +5 -0
- package/.eslintrc.json +3 -0
- package/LICENSE +21 -0
- package/README.md +398 -0
- package/app/globals.css +170 -0
- package/app/layout.tsx +29 -0
- package/app/page.tsx +289 -0
- package/assets/banner.svg +76 -0
- package/bin/create-app.js +99 -0
- package/components/3d/CyberCity.tsx +260 -0
- package/components/animations/CyberGrid.tsx +13 -0
- package/components/animations/GlitchText.tsx +17 -0
- package/components/animations/Hero.tsx +88 -0
- package/components/effects/Particles.tsx +180 -0
- package/components/effects/ScanLines.tsx +5 -0
- package/components/hooks/useAudioReactive.ts +68 -0
- package/components/hooks/useGlitch.ts +26 -0
- package/components/hooks/useNeonGlow.ts +31 -0
- package/components/hooks/useParallax.ts +23 -0
- package/components/ui/CyberNav.tsx +129 -0
- package/components/ui/HologramCard.tsx +107 -0
- package/components/ui/NeonButton.tsx +27 -0
- package/components/ui/Terminal.tsx +56 -0
- package/next-env.d.ts +6 -0
- package/next.config.ts +16 -0
- package/package.json +61 -0
- package/postcss.config.mjs +9 -0
- package/styles/animations.css +204 -0
- package/styles/glitch.css +273 -0
- package/styles/neon.css +130 -0
- package/tailwind.config.ts +112 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
export function useParallax(speed: number = 0.5) {
|
|
6
|
+
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const handleMouseMove = (e: MouseEvent) => {
|
|
10
|
+
const x = (e.clientX - window.innerWidth / 2) * speed;
|
|
11
|
+
const y = (e.clientY - window.innerHeight / 2) * speed;
|
|
12
|
+
setOffset({ x, y });
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
16
|
+
|
|
17
|
+
return () => {
|
|
18
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
19
|
+
};
|
|
20
|
+
}, [speed]);
|
|
21
|
+
|
|
22
|
+
return offset;
|
|
23
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
export default function CyberNav() {
|
|
6
|
+
const [isScrolled, setIsScrolled] = useState(false);
|
|
7
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const handleScroll = () => {
|
|
11
|
+
setIsScrolled(window.scrollY > 50);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
window.addEventListener('scroll', handleScroll);
|
|
15
|
+
return () => window.removeEventListener('scroll', handleScroll);
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
const navItems = [
|
|
19
|
+
{ name: 'Home', href: '#home' },
|
|
20
|
+
{ name: 'Portfolio', href: '#portfolio' },
|
|
21
|
+
{ name: 'Skills', href: '#skills' },
|
|
22
|
+
{ name: 'Blog', href: '#blog' },
|
|
23
|
+
{ name: 'About', href: '#about' },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const scrollToSection = (id: string) => {
|
|
27
|
+
const element = document.getElementById(id);
|
|
28
|
+
element?.scrollIntoView({ behavior: 'smooth' });
|
|
29
|
+
setIsMenuOpen(false);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<nav
|
|
34
|
+
className={`fixed top-4 left-4 right-4 z-50 transition-all duration-300 rounded-xl ${
|
|
35
|
+
isScrolled ? 'glass backdrop-blur-md shadow-lg shadow-neon-cyan/10' : 'bg-transparent'
|
|
36
|
+
}`}
|
|
37
|
+
>
|
|
38
|
+
<div className="container mx-auto px-4">
|
|
39
|
+
<div className="flex items-center justify-between h-20">
|
|
40
|
+
{/* Logo */}
|
|
41
|
+
<a
|
|
42
|
+
href="#home"
|
|
43
|
+
onClick={(e) => {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
scrollToSection('home');
|
|
46
|
+
}}
|
|
47
|
+
className="font-orbitron text-2xl font-bold text-neon-cyan cursor-pointer"
|
|
48
|
+
>
|
|
49
|
+
<span className="neon-text-cyan">NEON</span>
|
|
50
|
+
<span className="neon-text-pink ml-2">FLUX</span>
|
|
51
|
+
</a>
|
|
52
|
+
|
|
53
|
+
{/* Desktop Menu */}
|
|
54
|
+
<ul className="hidden md:flex space-x-8">
|
|
55
|
+
{navItems.map((item, index) => (
|
|
56
|
+
<li key={index}>
|
|
57
|
+
<a
|
|
58
|
+
href={item.href}
|
|
59
|
+
onClick={(e) => {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
scrollToSection(item.href.substring(1));
|
|
62
|
+
}}
|
|
63
|
+
className="font-rajdhani text-lg text-neon-cyan hover:text-neon-pink transition-colors duration-300 neon-glow-hover cursor-pointer focus:outline-none focus:text-neon-pink"
|
|
64
|
+
>
|
|
65
|
+
{item.name}
|
|
66
|
+
</a>
|
|
67
|
+
</li>
|
|
68
|
+
))}
|
|
69
|
+
</ul>
|
|
70
|
+
|
|
71
|
+
{/* CTA Button */}
|
|
72
|
+
<button
|
|
73
|
+
className="hidden md:block neon-button text-sm"
|
|
74
|
+
onClick={() => scrollToSection('portfolio')}
|
|
75
|
+
>
|
|
76
|
+
View Portfolio
|
|
77
|
+
</button>
|
|
78
|
+
|
|
79
|
+
{/* Mobile Menu Button */}
|
|
80
|
+
<button
|
|
81
|
+
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
|
82
|
+
className="md:hidden text-neon-cyan cursor-pointer focus:outline-none focus:ring-2 focus:ring-neon-cyan focus:ring-offset-2 focus:ring-offset-cyber-black rounded-md p-1"
|
|
83
|
+
aria-label="Toggle menu"
|
|
84
|
+
>
|
|
85
|
+
<div className="w-6 h-5 flex flex-col justify-between">
|
|
86
|
+
<span
|
|
87
|
+
className={`block h-0.5 w-full bg-current transform transition-all duration-300 ${
|
|
88
|
+
isMenuOpen ? 'rotate-45 translate-y-2' : ''
|
|
89
|
+
}`}
|
|
90
|
+
/>
|
|
91
|
+
<span
|
|
92
|
+
className={`block h-0.5 w-full bg-current transition-all duration-300 ${
|
|
93
|
+
isMenuOpen ? 'opacity-0' : 'opacity-100'
|
|
94
|
+
}`}
|
|
95
|
+
/>
|
|
96
|
+
<span
|
|
97
|
+
className={`block h-0.5 w-full bg-current transform transition-all duration-300 ${
|
|
98
|
+
isMenuOpen ? '-rotate-45 -translate-y-2' : ''
|
|
99
|
+
}`}
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
{/* Mobile Menu */}
|
|
106
|
+
{isMenuOpen && (
|
|
107
|
+
<div className="md:hidden glass rounded-lg mt-2 mb-4 p-4">
|
|
108
|
+
<ul className="space-y-4">
|
|
109
|
+
{navItems.map((item, index) => (
|
|
110
|
+
<li key={index}>
|
|
111
|
+
<a
|
|
112
|
+
href={item.href}
|
|
113
|
+
onClick={(e) => {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
scrollToSection(item.href.substring(1));
|
|
116
|
+
}}
|
|
117
|
+
className="block font-rajdhani text-lg text-neon-cyan hover:text-neon-pink transition-colors duration-300 cursor-pointer focus:outline-none focus:text-neon-pink"
|
|
118
|
+
>
|
|
119
|
+
{item.name}
|
|
120
|
+
</a>
|
|
121
|
+
</li>
|
|
122
|
+
))}
|
|
123
|
+
</ul>
|
|
124
|
+
</div>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
</nav>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { motion } from 'framer-motion';
|
|
4
|
+
import { ReactNode, useState } from 'react';
|
|
5
|
+
import Image from 'next/image';
|
|
6
|
+
|
|
7
|
+
interface HologramCardProps {
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
image?: string;
|
|
11
|
+
tags?: string[];
|
|
12
|
+
link?: string;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
delay?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function HologramCard({
|
|
18
|
+
title,
|
|
19
|
+
description,
|
|
20
|
+
image,
|
|
21
|
+
tags = [],
|
|
22
|
+
link,
|
|
23
|
+
children,
|
|
24
|
+
delay = 0,
|
|
25
|
+
}: HologramCardProps) {
|
|
26
|
+
const [imageLoaded, setImageLoaded] = useState(false);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<motion.div
|
|
30
|
+
initial={{ opacity: 0, y: 50 }}
|
|
31
|
+
whileInView={{ opacity: 1, y: 0 }}
|
|
32
|
+
transition={{ duration: 0.6, delay }}
|
|
33
|
+
viewport={{ once: true }}
|
|
34
|
+
className="group relative glass rounded-lg p-6 cursor-pointer hover:shadow-neon-cyan hover:border-neon-cyan/50 transition-all duration-300"
|
|
35
|
+
>
|
|
36
|
+
{/* Hologram border effect - single cyan glow */}
|
|
37
|
+
<div className="absolute inset-0 rounded-lg bg-neon-cyan/30 opacity-0 group-hover:opacity-100 transition-opacity duration-300 blur-md" />
|
|
38
|
+
|
|
39
|
+
<div className="relative z-10">
|
|
40
|
+
{/* Image */}
|
|
41
|
+
{image && (
|
|
42
|
+
<div className="relative w-full h-48 mb-4 rounded-lg overflow-hidden bg-cyber-dark">
|
|
43
|
+
{/* Skeleton loader */}
|
|
44
|
+
{!imageLoaded && (
|
|
45
|
+
<div className="absolute inset-0 bg-cyber-dark animate-pulse">
|
|
46
|
+
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-neon-cyan/5 to-transparent animate-[shimmer_2s_infinite]" />
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
<Image
|
|
50
|
+
src={image}
|
|
51
|
+
alt={title}
|
|
52
|
+
fill
|
|
53
|
+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
54
|
+
className={`object-cover transition-opacity duration-500 ${imageLoaded ? 'opacity-100' : 'opacity-0'}`}
|
|
55
|
+
onLoad={() => setImageLoaded(true)}
|
|
56
|
+
loading="lazy"
|
|
57
|
+
/>
|
|
58
|
+
<div className="absolute inset-0 bg-gradient-to-t from-cyber-black/80 to-transparent" />
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
61
|
+
|
|
62
|
+
{/* Title */}
|
|
63
|
+
<h3 className="text-2xl font-orbitron font-bold text-neon-cyan mb-3 group-hover:text-neon-pink transition-colors">
|
|
64
|
+
{title}
|
|
65
|
+
</h3>
|
|
66
|
+
|
|
67
|
+
{/* Description */}
|
|
68
|
+
<p className="text-neon-cyan/80 mb-4 leading-relaxed">{description}</p>
|
|
69
|
+
|
|
70
|
+
{/* Tags */}
|
|
71
|
+
{tags.length > 0 && (
|
|
72
|
+
<div className="flex flex-wrap gap-2 mb-4">
|
|
73
|
+
{tags.map((tag, index) => (
|
|
74
|
+
<span
|
|
75
|
+
key={index}
|
|
76
|
+
className="px-3 py-1 text-xs font-space-mono bg-cyber-dark border border-neon-cyan/30 text-neon-cyan rounded-full"
|
|
77
|
+
>
|
|
78
|
+
{tag}
|
|
79
|
+
</span>
|
|
80
|
+
))}
|
|
81
|
+
</div>
|
|
82
|
+
)}
|
|
83
|
+
|
|
84
|
+
{/* Custom children */}
|
|
85
|
+
{children}
|
|
86
|
+
|
|
87
|
+
{/* Link */}
|
|
88
|
+
{link && (
|
|
89
|
+
<a
|
|
90
|
+
href={link}
|
|
91
|
+
target="_blank"
|
|
92
|
+
rel="noopener noreferrer"
|
|
93
|
+
className="inline-block mt-4 text-neon-pink hover:text-neon-yellow transition-colors font-space-mono cursor-pointer focus:outline-none focus:ring-2 focus:ring-neon-pink focus:ring-offset-2 focus:ring-offset-cyber-black rounded"
|
|
94
|
+
>
|
|
95
|
+
View Project →
|
|
96
|
+
</a>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
{/* Corner accents */}
|
|
101
|
+
<div className="absolute top-0 left-0 w-4 h-4 border-t-2 border-l-2 border-neon-cyan" />
|
|
102
|
+
<div className="absolute top-0 right-0 w-4 h-4 border-t-2 border-r-2 border-neon-cyan" />
|
|
103
|
+
<div className="absolute bottom-0 left-0 w-4 h-4 border-b-2 border-l-2 border-neon-cyan" />
|
|
104
|
+
<div className="absolute bottom-0 right-0 w-4 h-4 border-b-2 border-r-2 border-neon-cyan" />
|
|
105
|
+
</motion.div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ButtonHTMLAttributes } from 'react';
|
|
4
|
+
|
|
5
|
+
interface NeonButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
6
|
+
variant?: 'primary' | 'secondary';
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function NeonButton({
|
|
11
|
+
variant = 'primary',
|
|
12
|
+
children,
|
|
13
|
+
className = '',
|
|
14
|
+
...props
|
|
15
|
+
}: NeonButtonProps) {
|
|
16
|
+
const baseClasses = 'neon-button neon-pulse';
|
|
17
|
+
const variantClasses = variant === 'primary' ? '' : 'neon-border-pink text-neon-pink';
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<button
|
|
21
|
+
className={`${baseClasses} ${variantClasses} ${className}`}
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
</button>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
const commands = [
|
|
6
|
+
{ cmd: '$ initializing_neon_flux...', delay: 0 },
|
|
7
|
+
{ cmd: '> Loading cyberpunk assets...', delay: 800 },
|
|
8
|
+
{ cmd: '> Compiling shaders... [OK]', delay: 1600 },
|
|
9
|
+
{ cmd: '> Establishing neural link... [OK]', delay: 2400 },
|
|
10
|
+
{ cmd: '> System ready. Welcome to the future.', delay: 3200 },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export default function Terminal() {
|
|
14
|
+
const [visibleCommands, setVisibleCommands] = useState<number>(0);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (visibleCommands < commands.length) {
|
|
18
|
+
const timer = setTimeout(() => {
|
|
19
|
+
setVisibleCommands((prev) => prev + 1);
|
|
20
|
+
}, commands[visibleCommands].delay);
|
|
21
|
+
|
|
22
|
+
return () => clearTimeout(timer);
|
|
23
|
+
}
|
|
24
|
+
}, [visibleCommands]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="glass rounded-lg p-6 font-space-mono text-sm">
|
|
28
|
+
{/* Terminal header */}
|
|
29
|
+
<div className="flex items-center gap-2 mb-4 pb-3 border-b border-neon-cyan/20">
|
|
30
|
+
<div className="w-3 h-3 rounded-full bg-neon-pink" />
|
|
31
|
+
<div className="w-3 h-3 rounded-full bg-neon-yellow" />
|
|
32
|
+
<div className="w-3 h-3 rounded-full bg-neon-cyan" />
|
|
33
|
+
<span className="ml-2 text-neon-cyan/60">terminal.jsx</span>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
{/* Terminal content */}
|
|
37
|
+
<div className="space-y-2">
|
|
38
|
+
{commands.slice(0, visibleCommands).map((item, index) => (
|
|
39
|
+
<div
|
|
40
|
+
key={index}
|
|
41
|
+
className="text-neon-cyan animate-pulse"
|
|
42
|
+
style={{ animationDuration: '1s' }}
|
|
43
|
+
>
|
|
44
|
+
{item.cmd}
|
|
45
|
+
</div>
|
|
46
|
+
))}
|
|
47
|
+
{visibleCommands === commands.length && (
|
|
48
|
+
<div className="flex items-center gap-2 mt-4">
|
|
49
|
+
<span className="text-neon-pink">$</span>
|
|
50
|
+
<span className="text-neon-cyan animate-pulse">_</span>
|
|
51
|
+
</div>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
package/next-env.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="next" />
|
|
2
|
+
/// <reference types="next/image-types/global" />
|
|
3
|
+
/// <reference path="./.next/types/routes.d.ts" />
|
|
4
|
+
|
|
5
|
+
// NOTE: This file should not be edited
|
|
6
|
+
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
package/next.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
reactStrictMode: true,
|
|
5
|
+
transpilePackages: ["gsap"],
|
|
6
|
+
images: {
|
|
7
|
+
remotePatterns: [
|
|
8
|
+
{
|
|
9
|
+
protocol: "https",
|
|
10
|
+
hostname: "images.unsplash.com",
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default nextConfig;
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-neon-flux",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cyberpunk Neon themed Next.js template with rich 3D animations",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"nextjs",
|
|
7
|
+
"template",
|
|
8
|
+
"cyberpunk",
|
|
9
|
+
"neon",
|
|
10
|
+
"gsap",
|
|
11
|
+
"animation",
|
|
12
|
+
"canvas",
|
|
13
|
+
"glitch",
|
|
14
|
+
"hologram"
|
|
15
|
+
],
|
|
16
|
+
"author": "kpab",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/kpab/neon-flux-template.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/kpab/neon-flux-template/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/kpab/neon-flux-template#readme",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "next dev",
|
|
28
|
+
"build": "next build",
|
|
29
|
+
"start": "next start",
|
|
30
|
+
"lint": "next lint",
|
|
31
|
+
"create-app": "node ./bin/create-app.js"
|
|
32
|
+
},
|
|
33
|
+
"bin": {
|
|
34
|
+
"create-neon-flux": "./bin/create-app.js"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"clsx": "^2.1.0",
|
|
38
|
+
"framer-motion": "^11.0.0",
|
|
39
|
+
"gsap": "^3.12.0",
|
|
40
|
+
"lucide-react": "^0.562.0",
|
|
41
|
+
"next": "^15.0.0",
|
|
42
|
+
"react": "^18.3.0",
|
|
43
|
+
"react-dom": "^18.3.0",
|
|
44
|
+
"tailwind-merge": "^2.2.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^20.0.0",
|
|
48
|
+
"@types/react": "^18.3.0",
|
|
49
|
+
"@types/react-dom": "^18.3.0",
|
|
50
|
+
"autoprefixer": "^10.4.0",
|
|
51
|
+
"eslint": "^8.0.0",
|
|
52
|
+
"eslint-config-next": "^15.0.0",
|
|
53
|
+
"postcss": "^8.4.0",
|
|
54
|
+
"tailwindcss": "^3.4.19",
|
|
55
|
+
"typescript": "^5.3.0"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=18.0.0",
|
|
59
|
+
"npm": ">=9.0.0"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/* Scan Lines Effect */
|
|
2
|
+
.scan-lines {
|
|
3
|
+
position: fixed;
|
|
4
|
+
top: 0;
|
|
5
|
+
left: 0;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
pointer-events: none;
|
|
9
|
+
z-index: 1000;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.scan-lines::before {
|
|
14
|
+
content: '';
|
|
15
|
+
position: absolute;
|
|
16
|
+
top: 0;
|
|
17
|
+
left: 0;
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 2px;
|
|
20
|
+
background: linear-gradient(
|
|
21
|
+
to bottom,
|
|
22
|
+
transparent 0%,
|
|
23
|
+
rgba(0, 255, 240, 0.8) 50%,
|
|
24
|
+
transparent 100%
|
|
25
|
+
);
|
|
26
|
+
animation: scan-line 8s linear infinite;
|
|
27
|
+
box-shadow: 0 0 10px var(--neon-cyan);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.scan-lines::after {
|
|
31
|
+
content: '';
|
|
32
|
+
position: absolute;
|
|
33
|
+
top: 0;
|
|
34
|
+
left: 0;
|
|
35
|
+
width: 100%;
|
|
36
|
+
height: 100%;
|
|
37
|
+
background: repeating-linear-gradient(
|
|
38
|
+
to bottom,
|
|
39
|
+
transparent 0px,
|
|
40
|
+
rgba(0, 255, 240, 0.03) 1px,
|
|
41
|
+
transparent 2px
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@keyframes scan-line {
|
|
46
|
+
0% {
|
|
47
|
+
transform: translateY(-100%);
|
|
48
|
+
}
|
|
49
|
+
100% {
|
|
50
|
+
transform: translateY(100vh);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Floating Animation */
|
|
55
|
+
.float-animation {
|
|
56
|
+
animation: float 6s ease-in-out infinite;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@keyframes float {
|
|
60
|
+
0%, 100% {
|
|
61
|
+
transform: translateY(0px);
|
|
62
|
+
}
|
|
63
|
+
50% {
|
|
64
|
+
transform: translateY(-20px);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Fade In Animations */
|
|
69
|
+
.fade-in {
|
|
70
|
+
animation: fade-in 1s ease-in forwards;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.fade-in-up {
|
|
74
|
+
animation: fade-in-up 1s ease-out forwards;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.fade-in-down {
|
|
78
|
+
animation: fade-in-down 1s ease-out forwards;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@keyframes fade-in {
|
|
82
|
+
from {
|
|
83
|
+
opacity: 0;
|
|
84
|
+
}
|
|
85
|
+
to {
|
|
86
|
+
opacity: 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes fade-in-up {
|
|
91
|
+
from {
|
|
92
|
+
opacity: 0;
|
|
93
|
+
transform: translateY(30px);
|
|
94
|
+
}
|
|
95
|
+
to {
|
|
96
|
+
opacity: 1;
|
|
97
|
+
transform: translateY(0);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@keyframes fade-in-down {
|
|
102
|
+
from {
|
|
103
|
+
opacity: 0;
|
|
104
|
+
transform: translateY(-30px);
|
|
105
|
+
}
|
|
106
|
+
to {
|
|
107
|
+
opacity: 1;
|
|
108
|
+
transform: translateY(0);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Slide In Animations */
|
|
113
|
+
.slide-in-left {
|
|
114
|
+
animation: slide-in-left 1s ease-out forwards;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.slide-in-right {
|
|
118
|
+
animation: slide-in-right 1s ease-out forwards;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@keyframes slide-in-left {
|
|
122
|
+
from {
|
|
123
|
+
opacity: 0;
|
|
124
|
+
transform: translateX(-50px);
|
|
125
|
+
}
|
|
126
|
+
to {
|
|
127
|
+
opacity: 1;
|
|
128
|
+
transform: translateX(0);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes slide-in-right {
|
|
133
|
+
from {
|
|
134
|
+
opacity: 0;
|
|
135
|
+
transform: translateX(50px);
|
|
136
|
+
}
|
|
137
|
+
to {
|
|
138
|
+
opacity: 1;
|
|
139
|
+
transform: translateX(0);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Typewriter Effect */
|
|
144
|
+
.typewriter {
|
|
145
|
+
overflow: hidden;
|
|
146
|
+
border-right: 2px solid var(--neon-cyan);
|
|
147
|
+
white-space: nowrap;
|
|
148
|
+
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@keyframes typing {
|
|
152
|
+
from {
|
|
153
|
+
width: 0;
|
|
154
|
+
}
|
|
155
|
+
to {
|
|
156
|
+
width: 100%;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@keyframes blink-caret {
|
|
161
|
+
from, to {
|
|
162
|
+
border-color: transparent;
|
|
163
|
+
}
|
|
164
|
+
50% {
|
|
165
|
+
border-color: var(--neon-cyan);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* Loading Animation */
|
|
170
|
+
.cyber-loader {
|
|
171
|
+
width: 50px;
|
|
172
|
+
height: 50px;
|
|
173
|
+
border: 3px solid var(--cyber-dark);
|
|
174
|
+
border-top-color: var(--neon-cyan);
|
|
175
|
+
border-radius: 50%;
|
|
176
|
+
animation: spin 1s linear infinite;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@keyframes spin {
|
|
180
|
+
to {
|
|
181
|
+
transform: rotate(360deg);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Delay utilities */
|
|
186
|
+
.delay-100 {
|
|
187
|
+
animation-delay: 0.1s;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.delay-200 {
|
|
191
|
+
animation-delay: 0.2s;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.delay-300 {
|
|
195
|
+
animation-delay: 0.3s;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.delay-400 {
|
|
199
|
+
animation-delay: 0.4s;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.delay-500 {
|
|
203
|
+
animation-delay: 0.5s;
|
|
204
|
+
}
|