404lab 2.0.1 → 2.0.3

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.
@@ -21,6 +21,7 @@ export const TEMPLATES = {
21
21
  snow: "Snow",
22
22
  strangethings: "StrangerThings",
23
23
  terminal: "Terminal404",
24
+ vercel: "Vercel"
24
25
  };
25
26
 
26
27
  export function getTemplateKeys() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "404lab",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "A CLI tool for generating beautiful custom 404 pages in Next.js projects",
5
5
  "type": "module",
6
6
  "preferGlobal": true,
@@ -20,13 +20,13 @@
20
20
  "generator",
21
21
  "templates"
22
22
  ],
23
- "author": "Your Name <your.email@example.com>",
23
+ "author": "Shreeteja Mutukundu <smutukundu2206@gmail.com>",
24
24
  "license": "MIT",
25
25
  "engines": {
26
26
  "node": ">=16.0.0"
27
27
  },
28
28
  "repository": {
29
29
  "type": "git",
30
- "url": "https://github.com/yourusername/404lab.git"
30
+ "url": "https://github.com/shreeteja172/404lab.git"
31
31
  }
32
32
  }
@@ -1,152 +1,246 @@
1
1
  "use client";
2
2
 
3
- import { useEffect, useRef } from "react";
3
+ import { useEffect, useRef, useState } from "react";
4
4
  import Image from "next/image";
5
5
  import Link from "next/link";
6
+ import { motion } from "framer-motion";
7
+ import { cn } from "@/components/ui/cn";
6
8
 
7
- const AmongUs = () => {
9
+ const AmongUs = ({ className }: { className?: string }) => {
8
10
  const containerRef = useRef<HTMLDivElement | null>(null);
11
+ const [stars, setStars] = useState<{ id: number; x: number; y: number; size: number; speed: number; opacity: number }[]>([]);
9
12
 
10
13
  useEffect(() => {
11
- const container = containerRef.current;
12
- if (!container) return;
13
-
14
- const createStar = () => {
15
- const { width, height } = container.getBoundingClientRect();
16
- let right = Math.random() * Math.max(width, 1);
17
- const top = Math.random() * Math.max(height, 1);
18
-
19
- const star = document.createElement("div");
20
- star.className =
21
- "star pointer-events-none absolute w-[2px] h-[2px] bg-white animate-starTwinkle";
22
- star.style.top = `${top}px`;
23
- star.style.right = `${right}px`;
24
-
25
- container.appendChild(star);
26
-
27
- const runStar = setInterval(() => {
28
- if (right >= width) {
29
- star.remove();
30
- clearInterval(runStar);
31
- }
32
- right += 3;
33
- star.style.right = `${right}px`;
34
- }, 10);
35
- };
14
+ const initialStars = Array.from({ length: 100 }).map((_, i) => ({
15
+ id: i,
16
+ x: Math.random() * 100,
17
+ y: Math.random() * 100,
18
+ size: Math.random() * 2 + 0.5,
19
+ speed: Math.random() * 1.5 + 0.5,
20
+ opacity: Math.random() * 0.7 + 0.3,
21
+ }));
22
+ setStars(initialStars);
23
+ }, []);
36
24
 
37
- const starInterval = setInterval(createStar, 120);
25
+ const typewriterVariants = {
26
+ hidden: { opacity: 0 },
27
+ visible: {
28
+ opacity: 1,
29
+ transition: {
30
+ staggerChildren: 0.08,
31
+ },
32
+ },
33
+ };
38
34
 
39
- return () => {
40
- clearInterval(starInterval);
41
- container.querySelectorAll(".star").forEach((s) => s.remove());
42
- };
43
- }, []);
35
+ const letterVariants = {
36
+ hidden: { opacity: 0, y: 5 },
37
+ visible: { opacity: 1, y: 0 },
38
+ };
39
+
40
+ const text = "There is 1 Impostor among us";
44
41
 
45
42
  return (
46
43
  <div
47
44
  ref={containerRef}
48
- className="relative flex h-screen w-full items-center justify-center overflow-hidden bg-gradient-to-t from-[#2e1753] via-[#1f1746] to-[#050819] text-white font-['Tomorrow']"
45
+ className={cn(
46
+ "relative flex h-screen w-full flex-col items-center justify-center overflow-hidden bg-[#000000] text-white",
47
+ className
48
+ )}
49
49
  >
50
- <div className="absolute top-[8%] text-center">
51
- <p className="text-red-400 tracking-[0.3em] text-sm">
52
- THERE IS 1 IMPOSTOR AMONG US
53
- </p>
54
- <h1 className="text-7xl font-extrabold mt-2">404</h1>
55
- <p className="mt-2 opacity-80">This page was ejected into space.</p>
56
-
57
- <Link
58
- href="/"
59
- className="inline-block mt-6 rounded-md bg-red-500 px-5 py-2 text-sm font-semibold hover:opacity-90 transition"
60
- >
61
- Return to Ship
62
- </Link>
63
- </div>
64
-
65
- <Image
66
- src="https://cdn.iconscout.com/icon/free/png-256/free-red-among-us-icon-svg-download-png-2691060.png"
67
- alt="Impostor"
68
- width={120}
69
- height={120}
70
- unoptimized
71
- className="absolute top-[55%] w-24 h-auto animate-astronautFly"
72
- />
73
-
74
- <Image
75
- src="https://cdn.iconscout.com/icon/free/png-256/free-blue-among-us-icon-svg-download-png-2691064.png"
76
- alt="Crewmate"
77
- width={120}
78
- height={120}
79
- unoptimized
80
- className="absolute bottom-[10%] left-[15%] w-24 h-auto animate-floatCrew"
81
- />
82
-
83
50
  <style jsx global>{`
84
- @keyframes astronautFly {
85
- 0% {
86
- left: -120px;
87
- }
88
- 25% {
89
- top: 52%;
90
- transform: rotate(10deg);
91
- }
92
- 50% {
93
- top: 58%;
94
- transform: rotate(20deg);
95
- }
96
- 75% {
97
- top: 62%;
98
- transform: rotate(10deg);
99
- }
100
- 100% {
101
- left: 110%;
102
- transform: rotate(20deg);
103
- }
51
+ @import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');
52
+
53
+ .among-us-font {
54
+ font-family: 'VT323', monospace;
104
55
  }
105
56
 
106
- @keyframes floatCrew {
107
- 0% {
108
- transform: translateY(0px);
109
- }
110
- 50% {
111
- transform: translateY(-12px);
112
- }
113
- 100% {
114
- transform: translateY(0px);
115
- }
57
+ .star-field {
58
+ position: absolute;
59
+ inset: 0;
60
+ pointer-events: none;
116
61
  }
117
62
 
118
- @keyframes starTwinkle {
119
- 0% {
120
- background: rgba(255, 255, 255, 0.4);
121
- }
122
- 25% {
123
- background: rgba(255, 255, 255, 0.8);
124
- }
125
- 50% {
126
- background: rgba(255, 255, 255, 1);
127
- }
128
- 75% {
129
- background: rgba(255, 255, 255, 0.8);
130
- }
131
- 100% {
132
- background: rgba(255, 255, 255, 0.4);
133
- }
63
+ .star {
64
+ position: absolute;
65
+ background: white;
66
+ border-radius: 50%;
134
67
  }
135
68
 
136
- .animate-astronautFly {
137
- animation: astronautFly 7s linear infinite;
69
+ .crt-overlay::before {
70
+ content: " ";
71
+ display: block;
72
+ position: absolute;
73
+ top: 0;
74
+ left: 0;
75
+ bottom: 0;
76
+ right: 0;
77
+ background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
78
+ z-index: 30;
79
+ background-size: 100% 3px, 3px 100%;
80
+ pointer-events: none;
138
81
  }
139
82
 
140
- .animate-starTwinkle {
141
- animation: starTwinkle 3s linear infinite;
83
+ .crt-scanline {
84
+ width: 100%;
85
+ height: 100px;
86
+ z-index: 31;
87
+ background: linear-gradient(0deg, rgba(0, 0, 0, 0) 0%, rgba(255, 255, 255, 0.05) 10%, rgba(0, 0, 0, 0.1) 100%);
88
+ opacity: 0.1;
89
+ position: absolute;
90
+ bottom: 100%;
91
+ animation: scanline 8s linear infinite;
142
92
  }
143
93
 
144
- .animate-floatCrew {
145
- animation: floatCrew 3s ease-in-out infinite;
94
+ @keyframes scanline {
95
+ 0% { bottom: 100%; }
96
+ 100% { bottom: -100px; }
146
97
  }
147
98
  `}</style>
99
+
100
+ <div className="star-field">
101
+ {stars.map((star) => (
102
+ <motion.div
103
+ key={star.id}
104
+ className="star"
105
+ style={{
106
+ width: star.size,
107
+ height: star.size,
108
+ top: `${star.y}%`,
109
+ left: `${star.x}%`,
110
+ opacity: star.opacity,
111
+ boxShadow: `0 0 ${star.size * 2}px rgba(255, 255, 255, 0.5)`,
112
+ }}
113
+ animate={{
114
+ left: ["100%", "-10%"],
115
+ }}
116
+ transition={{
117
+ duration: 25 / star.speed,
118
+ repeat: Infinity,
119
+ ease: "linear",
120
+ delay: Math.random() * -25,
121
+ }}
122
+ />
123
+ ))}
124
+ </div>
125
+
126
+ <div className="z-10 flex flex-col items-center text-center px-4 among-us-font select-none">
127
+ <motion.h1
128
+ className="text-8xl md:text-[12rem] font-bold tracking-[0.1em] text-white mb-4 leading-none"
129
+ initial={{ opacity: 0, scale: 0.9 }}
130
+ animate={{ opacity: 1, scale: 1 }}
131
+ transition={{ duration: 1.5, ease: "easeOut" }}
132
+ >
133
+ 404
134
+ </motion.h1>
135
+
136
+ <motion.div
137
+ className="mb-8 h-12"
138
+ variants={typewriterVariants}
139
+ initial="hidden"
140
+ animate="visible"
141
+ >
142
+ <h2 className="text-2xl md:text-5xl text-red-500 uppercase font-black tracking-[0.2em]">
143
+ {text.split("").map((char, index) => (
144
+ <motion.span key={index} variants={letterVariants}>
145
+ {char}
146
+ </motion.span>
147
+ ))}
148
+ </h2>
149
+ </motion.div>
150
+
151
+ <motion.div
152
+ className="space-y-6"
153
+ initial={{ opacity: 0 }}
154
+ animate={{ opacity: 1 }}
155
+ transition={{ delay: 3.5, duration: 1.2 }}
156
+ >
157
+ <p className="text-xl md:text-4xl text-gray-400 max-w-2xl mx-auto tracking-wide leading-relaxed">
158
+ This page was ejected into space.
159
+ </p>
160
+
161
+ <motion.p
162
+ className="text-lg md:text-3xl text-white tracking-widest"
163
+ initial={{ opacity: 0, y: 20 }}
164
+ animate={{ opacity: 1, y: 0 }}
165
+ transition={{ delay: 5, duration: 1 }}
166
+ >
167
+ <span className="text-red-600 font-bold px-2">404-Page</span> was not An Impostor.
168
+ </motion.p>
169
+
170
+ <motion.div
171
+ className="pt-12"
172
+ initial={{ opacity: 0 }}
173
+ animate={{ opacity: 1 }}
174
+ transition={{ delay: 6.5, duration: 1 }}
175
+ >
176
+ <Link
177
+ href="/"
178
+ className="group relative inline-flex items-center justify-center px-12 py-4 font-bold text-white transition-all duration-300 bg-transparent border-2 border-white/30 hover:border-white hover:bg-white hover:text-black rounded-sm uppercase tracking-[0.3em] text-xl"
179
+ >
180
+ Return to Ship
181
+ </Link>
182
+ </motion.div>
183
+ </motion.div>
184
+ </div>
185
+
186
+ <div className="absolute inset-0 pointer-events-none overflow-hidden">
187
+ <motion.div
188
+ className="absolute w-32 md:w-56 h-auto"
189
+ initial={{ left: "-25%", top: "40%", rotate: 0 }}
190
+ animate={{
191
+ left: "125%",
192
+ top: ["40%", "45%", "35%", "40%"],
193
+ rotate: 360
194
+ }}
195
+ transition={{
196
+ duration: 20,
197
+ repeat: Infinity,
198
+ ease: "linear"
199
+ }}
200
+ >
201
+ <Image
202
+ src="https://cdn.iconscout.com/icon/free/png-256/free-red-among-us-icon-svg-download-png-2691060.png"
203
+ alt="Ejected Red"
204
+ width={250}
205
+ height={250}
206
+ unoptimized
207
+ className="drop-shadow-[0_0_20px_rgba(255,0,0,0.5)]"
208
+ />
209
+ </motion.div>
210
+
211
+ <motion.div
212
+ className="absolute w-24 md:w-40 h-auto"
213
+ initial={{ left: "-25%", top: "70%", rotate: 0 }}
214
+ animate={{
215
+ left: "125%",
216
+ top: ["70%", "55%", "65%", "70%"],
217
+ rotate: -360
218
+ }}
219
+ transition={{
220
+ duration: 28,
221
+ repeat: Infinity,
222
+ ease: "linear",
223
+ delay: 12
224
+ }}
225
+ >
226
+ <Image
227
+ src="https://cdn.iconscout.com/icon/free/png-256/free-blue-among-us-icon-svg-download-png-2691064.png"
228
+ alt="Ejected Blue"
229
+ width={200}
230
+ height={200}
231
+ unoptimized
232
+ className="drop-shadow-[0_0_20px_rgba(0,0,255,0.5)] opacity-60"
233
+ />
234
+ </motion.div>
235
+ </div>
236
+
237
+ <div className="crt-overlay pointer-events-none absolute inset-0 z-40"></div>
238
+ <div className="crt-scanline z-50"></div>
239
+ <div className="absolute inset-0 pointer-events-none bg-[radial-gradient(circle_at_center,_transparent_0%,_rgba(0,0,0,0.7)_100%)] z-20"></div>
148
240
  </div>
149
241
  );
150
242
  };
151
243
 
152
244
  export default AmongUs;
245
+
246
+