CrosswordGPT instantly turns any topic you love into fun crossword puzzles. Unlike regular crosswords that come ready-made, this app creates endless puzzles just for you, matching your interests and how hard you want them to be. It's like having a personal puzzle maker that knows exactly what you enjoy. Built with Next.js and AI technology, this open-source template helps developers create their own puzzle apps. As more people look for smart ways to learn while having fun, this template lets you build your own crossword app quickly and easily.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
'use client';
import React, { useState, useEffect, useRef } from 'react';
import Link from 'next/link';
const CategoryIcon = ({ type }: { type: string }) => {
const icons = {
Science: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6m-6 4h6" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
History: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Geography: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Literature: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Movies: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M7 4v16M17 4v16M3 8h4m10 0h4M3 12h18M3 16h4m10 0h4M4 20h16a1 1 0 001-1V5a1 1 0 00-1-1H4a1 1 0 00-1 1v14a1 1 0 001 1z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Sports: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M12 14l9-5-9-5-9 5 9 5z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
<path d="M12 14l9-5-9-5-9 5 9 5zm0 0v10" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Technology: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Music: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M9 19V6l12-3v13M9 19c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zm12-3c0 1.105-1.343 2-3 2s-3-.895-3-2 1.343-2 3-2 3 .895 3 2zM9 10l12-3" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
)
};
return icons[type as keyof typeof icons] || null;
};
const DifficultyIcon = ({ level }: { level: string }) => {
const icons = {
Beginner: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Intermediate: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M13 10V3L4 14h7v7l9-11h-7z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
),
Hard: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" className="w-8 h-8">
<path d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
)
};
return icons[level as keyof typeof icons] || null;
};
const AnimatedCrossword = () => {
const words = [
{ word: 'DRIVE', positions: [0, 1, 2, 3, 4], direction: 'across', startDelay: 0 },
{ word: 'RIVER', positions: [1, 8, 15, 22, 29], direction: 'down', startDelay: 1000 },
{ word: 'SOLVE', positions: [12, 13, 14, 15, 16], direction: 'across', startDelay: 2000 }
];
const [activeLetters, setActiveLetters] = useState(new Map());
const gridSize = 6;
useEffect(() => {
let isAnimating = true;
let currentCycle = 0;
const animateSequence = async () => {
while (isAnimating) {
setActiveLetters(new Map());
await new Promise(resolve => setTimeout(resolve, 1000));
for (const { word, positions, startDelay } of words) {
await new Promise(resolve => setTimeout(resolve, startDelay));
for (let i = 0; i < word.length; i++) {
if (!isAnimating) return;
await new Promise(resolve => setTimeout(resolve, 400));
setActiveLetters(prev => {
const updated = new Map(prev);
updated.set(positions[i], word[i]);
return updated;
});
}
}
await new Promise(resolve => setTimeout(resolve, 2000));
currentCycle++;
}
};
animateSequence();
return () => {
isAnimating = false;
};
}, []);
return (
<div className="grid grid-cols-6 gap-1.5 w-96 h-96 rounded-2xl p-4 bg-white/50 backdrop-blur-sm">
{Array.from({ length: gridSize * gridSize }).map((_, index) => (
<div
key={index}
className={`
rounded-lg flex items-center justify-center
transition-all duration-300
shadow-[0_2px_10px_rgba(0,0,0,0.08)]
${activeLetters.has(index)
? 'bg-black text-white scale-105 shadow-lg'
: 'bg-white shadow-sm'}
`}
>
<span className="text-2xl font-bold">
{activeLetters.get(index) || ''}
</span>
</div>
))}
</div>
);
};
const CategoryCarousel = () => {
const categories = [
'Science', 'History', 'Geography', 'Literature',
'Movies', 'Sports', 'Technology', 'Music',
'Science', 'History', 'Geography', 'Literature',
'Movies', 'Sports', 'Technology', 'Music'
];
const carouselRef = useRef<HTMLDivElement>(null);
const [translateX, setTranslateX] = useState(0);
const [isPaused, setIsPaused] = useState(false);
useEffect(() => {
let animationFrameId: number;
let lastTime = performance.now();
const speed = 50;
const animate = (currentTime: number) => {
if (!isPaused) {
const deltaTime = currentTime - lastTime;
const movement = (speed * deltaTime) / 1000;
setTranslateX(prevTranslate => {
const newTranslate = prevTranslate - movement;
if (newTranslate <= -3200) {
return 0;
}
return newTranslate;
});
}
lastTime = currentTime;
animationFrameId = requestAnimationFrame(animate);
};
animationFrameId = requestAnimationFrame(animate);
return () => cancelAnimationFrame(animationFrameId);
}, [isPaused]);
return (
<div
className="relative group mx-auto max-w-[90vw] overflow-hidden"
onMouseEnter={() => setIsPaused(true)}
onMouseLeave={() => setIsPaused(false)}
>
<div
ref={carouselRef}
className="flex gap-6 py-8 transition-transform duration-100"
style={{
transform: `translateX(${translateX}px)`,
width: 'fit-content'
}}
>
{categories.map((category, index) => (
<div
key={`${category}-${index}`}
className="flex-none w-72 p-8 rounded-2xl
backdrop-blur-sm shadow-[0_8px_30px_rgb(0,0,0,0.2)]
bg-black text-white
transform hover:-translate-y-1
transition-all duration-500"
>
<div className="mb-6">
<CategoryIcon type={category} />
</div>
<h3 className="text-2xl font-bold mb-2">{category}</h3>
<p className="text-sm opacity-80">
Explore {category.toLowerCase()}-themed puzzles
</p>
</div>
))}
</div>
<div className="absolute top-0 left-0 w-20 h-full bg-gradient-to-r from-white to-transparent pointer-events-none" />
<div className="absolute top-0 right-0 w-20 h-full bg-gradient-to-l from-white to-transparent pointer-events-none" />
</div>
);
};
const gridPattern = {
backgroundImage: 'linear-gradient(90deg,rgba(0,0,0,.03) 1px,transparent 0),linear-gradient(180deg,rgba(0,0,0,.03) 1px,transparent 0)',
backgroundSize: '40px 40px'
};
export default function LandingPage() {
return (
<div className="min-h-screen bg-white" style={gridPattern}>
<nav className="fixed top-0 left-0 right-0 bg-white/80 backdrop-blur-md z-50 border-b border-black/5">
<div className="container mx-auto px-4 py-4 flex justify-between items-center">
<Link href="/" className="text-2xl font-bold">CrosswordGPT</Link>
<div className="flex gap-8 items-center">
<Link href="#categories" className="hover:opacity-70 transition-opacity">Categories</Link>
<Link
href="/puzzle"
className="bg-black text-white px-6 py-2 rounded-lg hover:bg-gray-800 transition-all duration-300"
>
Start Playing
</Link>
</div>
</div>
</nav>
<section className="pt-32 pb-20 relative">
<div className="absolute inset-0 bg-gradient-to-b from-gray-50 to-white opacity-50" />
<div className="container mx-auto px-4 relative">
<div className="grid md:grid-cols-2 gap-16 items-center">
<div className="pl-12 space-y-8">
<h1 className="text-7xl font-bold leading-tight">
AI Crossword
<br />
<span className="text-8xl bg-gradient-to-r from-black via-gray-700 to-black text-transparent bg-clip-text">
Puzzle
</span>
</h1>
<p className="text-xl text-gray-600">
Play cool AI-powered crossword puzzles based on your interests and skill level.
</p>
<Link
href="/puzzle"
className="inline-flex items-center gap-3 bg-black text-white px-12 py-6 rounded-xl
text-xl font-bold hover:bg-gray-900 transition-all duration-300
transform hover:-translate-y-1 shadow-lg hover:shadow-xl"
>
Create Your Puzzle
<span className="group-hover:translate-x-1 transition-transform">ā</span>
</Link>
</div>
<div className="relative">
<div className="absolute inset-0 bg-gradient-radial from-white via-transparent to-transparent z-10" />
<AnimatedCrossword />
</div>
</div>
</div>
</section>
<section id="categories" className="py-24 relative">
<div className="absolute inset-0 bg-gradient-to-b from-white via-gray-50 to-white opacity-50" />
<div className="container mx-auto px-4 relative">
<h2 className="text-5xl font-bold text-center mb-16 bg-gradient-to-r from-black via-gray-700 to-black text-transparent bg-clip-text">
Choose Your Category
</h2>
<CategoryCarousel />
</div>
</section>
<section className="py-10">
<div className="container mx-auto px-4">
<h2 className="text-5xl font-bold text-center mb-16 bg-gradient-to-r from-black via-gray-700 to-black text-transparent bg-clip-text">
Select Difficulty
</h2>
<div className="grid md:grid-cols-3 gap-8">
{[
{ level: 'Beginner', desc: 'Perfect for newcomers with friendly clues and simpler words' },
{ level: 'Intermediate', desc: 'Challenge yourself with more complex patterns and vocabulary' },
{ level: 'Hard', desc: 'Master-level puzzles for the truly dedicated solver' }
].map(({ level, desc }) => (
<div
key={level}
className="p-8 rounded-2xl cursor-pointer backdrop-blur-sm
shadow-[0_8px_30px_rgb(0,0,0,0.2)]
transform -translate-y-1
bg-black text-white
transition-all duration-300"
>
<div className="mb-6">
<DifficultyIcon level={level} />
</div>
<h3 className="text-2xl font-bold mb-4">{level}</h3>
<p>{desc}</p>
</div>
))}
</div>
</div>
</section>
<section className="py-24 relative">
<div className="absolute inset-0 bg-gradient-to-b from-gray-50 to-white opacity-50" />
<div className="container mx-auto px-4 relative max-w-3xl text-center">
<h2 className="text-5xl font-bold mb-6 bg-gradient-to-r from-black via-gray-700 to-black text-transparent bg-clip-text">
Ready to Start Playing?
</h2>
<p className="text-xl text-gray-600 mb-12">
Experience the next generation of crossword puzzles. Our AI creates unique puzzles tailored
to your interests, making every solving session engaging and enjoyable.
</p>
<div className="inline-flex gap-8">
<Link
href="/puzzle"
className="bg-black text-white px-8 py-4 rounded-xl
font-semibold hover:bg-gray-800 transition-all duration-300
transform hover:-translate-y-1 shadow-lg hover:shadow-xl
text-lg"
>
Create Your First Puzzle
</Link>
</div>
</div>
</section>
</div>
);
}
Last updated 3 months ago