LukasBe commited on
Commit
b9dd34e
·
verified ·
1 Parent(s): 526e121

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +1330 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Custom Rides Eshop
3
- emoji: 🐢
4
  colorFrom: red
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: custom-rides-eshop
3
+ emoji: 🐳
4
  colorFrom: red
5
+ colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1330 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Custom Rides - Design Your Dream Car</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
10
+ <style>
11
+ @import url('https://fonts.googleapis.com/css2?family=Racing+Sans+One&family=Poppins:wght@300;400;600;700&display=swap');
12
+
13
+ :root {
14
+ --primary: #ff3e00;
15
+ --secondary: #00c4cc;
16
+ --dark: #1a1a2e;
17
+ --light: #f5f5f5;
18
+ --accent: #ffcc00;
19
+ }
20
+
21
+ body {
22
+ font-family: 'Poppins', sans-serif;
23
+ background-color: var(--dark);
24
+ color: var(--light);
25
+ overflow-x: hidden;
26
+ }
27
+
28
+ .title-font {
29
+ font-family: 'Racing Sans One', cursive;
30
+ }
31
+
32
+ .car-container {
33
+ perspective: 1000px;
34
+ transition: all 0.5s ease;
35
+ }
36
+
37
+ .car-model {
38
+ transform-style: preserve-3d;
39
+ transition: transform 1s;
40
+ }
41
+
42
+ .sticker {
43
+ transition: all 0.3s ease;
44
+ cursor: grab;
45
+ }
46
+
47
+ .sticker:hover {
48
+ transform: scale(1.05);
49
+ filter: drop-shadow(0 0 8px rgba(255, 204, 0, 0.7));
50
+ }
51
+
52
+ .color-option {
53
+ width: 40px;
54
+ height: 40px;
55
+ border-radius: 50%;
56
+ cursor: pointer;
57
+ transition: all 0.3s ease;
58
+ border: 2px solid transparent;
59
+ }
60
+
61
+ .color-option:hover {
62
+ transform: scale(1.1);
63
+ border-color: white;
64
+ }
65
+
66
+ .color-option.selected {
67
+ transform: scale(1.2);
68
+ border-color: var(--accent);
69
+ box-shadow: 0 0 0 3px rgba(255, 204, 0, 0.3);
70
+ }
71
+
72
+ .sticker-category {
73
+ transition: all 0.3s ease;
74
+ }
75
+
76
+ .sticker-category:hover {
77
+ background-color: rgba(255, 62, 0, 0.2);
78
+ transform: translateY(-3px);
79
+ }
80
+
81
+ .sticker-category.active {
82
+ background-color: var(--primary);
83
+ color: white;
84
+ }
85
+
86
+ .intro-animation {
87
+ animation: slideIn 1s ease-out forwards;
88
+ }
89
+
90
+ @keyframes slideIn {
91
+ from {
92
+ transform: translateY(50px);
93
+ opacity: 0;
94
+ }
95
+ to {
96
+ transform: translateY(0);
97
+ opacity: 1;
98
+ }
99
+ }
100
+
101
+ .paint-effect {
102
+ position: absolute;
103
+ width: 100%;
104
+ height: 100%;
105
+ top: 0;
106
+ left: 0;
107
+ background: radial-gradient(circle, transparent 10%, rgba(255,255,255,0.3) 20%, transparent 30%);
108
+ opacity: 0;
109
+ pointer-events: none;
110
+ z-index: 10;
111
+ }
112
+
113
+ .confetti {
114
+ position: fixed;
115
+ width: 10px;
116
+ height: 10px;
117
+ background-color: var(--accent);
118
+ opacity: 0;
119
+ z-index: 1000;
120
+ animation: confetti-fall 3s ease-in forwards;
121
+ }
122
+
123
+ @keyframes confetti-fall {
124
+ 0% {
125
+ transform: translateY(-100px) rotate(0deg);
126
+ opacity: 1;
127
+ }
128
+ 100% {
129
+ transform: translateY(100vh) rotate(360deg);
130
+ opacity: 0;
131
+ }
132
+ }
133
+
134
+ .invalid-placement {
135
+ animation: shake 0.5s ease-in-out;
136
+ }
137
+
138
+ @keyframes shake {
139
+ 0%, 100% { transform: translateX(0); }
140
+ 20%, 60% { transform: translateX(-5px); }
141
+ 40%, 80% { transform: translateX(5px); }
142
+ }
143
+
144
+ .sticker-preview {
145
+ transition: all 0.3s ease;
146
+ filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.3));
147
+ }
148
+
149
+ .sticker-preview:hover {
150
+ transform: scale(1.1) rotate(5deg);
151
+ filter: drop-shadow(0 6px 8px rgba(0, 0, 0, 0.4));
152
+ }
153
+
154
+ .tooltip {
155
+ position: absolute;
156
+ background: rgba(0, 0, 0, 0.8);
157
+ color: white;
158
+ padding: 5px 10px;
159
+ border-radius: 5px;
160
+ font-size: 12px;
161
+ pointer-events: none;
162
+ z-index: 100;
163
+ opacity: 0;
164
+ transition: opacity 0.3s;
165
+ }
166
+
167
+ #webgl-container {
168
+ position: relative;
169
+ width: 100%;
170
+ height: 500px;
171
+ background: linear-gradient(135deg, #2a2a3a 0%, #1a1a2e 100%);
172
+ border-radius: 15px;
173
+ overflow: hidden;
174
+ }
175
+
176
+ .progress-bar {
177
+ height: 5px;
178
+ background: linear-gradient(90deg, var(--primary), var(--secondary));
179
+ transition: width 0.5s ease;
180
+ }
181
+
182
+ .neon-text {
183
+ text-shadow: 0 0 5px var(--primary), 0 0 10px var(--primary), 0 0 15px var(--primary);
184
+ }
185
+
186
+ .glow-effect {
187
+ box-shadow: 0 0 15px var(--accent);
188
+ }
189
+ </style>
190
+ </head>
191
+ <body class="min-h-screen">
192
+ <!-- Intro Screen -->
193
+ <div id="intro-screen" class="fixed inset-0 bg-black bg-opacity-90 flex flex-col items-center justify-center z-50 transition-all duration-1000">
194
+ <div class="intro-animation text-center max-w-2xl px-4">
195
+ <h1 class="title-font text-6xl md:text-8xl mb-6 text-transparent bg-clip-text bg-gradient-to-r from-orange-500 to-cyan-400 neon-text">
196
+ CUSTOM RIDES
197
+ </h1>
198
+ <p class="text-xl md:text-2xl mb-10 text-gray-300">
199
+ Design your dream car with our magical customization tool. Add stickers, change colors, and create a unique ride!
200
+ </p>
201
+ <button id="start-btn" class="px-10 py-4 bg-gradient-to-r from-orange-500 to-pink-600 text-white rounded-full text-xl font-bold hover:scale-105 transition-all duration-300 glow-effect">
202
+ START CUSTOMIZING <i class="fas fa-chevron-right ml-2"></i>
203
+ </button>
204
+ </div>
205
+ </div>
206
+
207
+ <!-- Main App Container -->
208
+ <div id="app-container" class="hidden container mx-auto px-4 py-8">
209
+ <!-- Header -->
210
+ <header class="flex justify-between items-center mb-8">
211
+ <h1 class="title-font text-3xl md:text-4xl text-transparent bg-clip-text bg-gradient-to-r from-orange-500 to-cyan-400">
212
+ CUSTOM RIDES
213
+ </h1>
214
+ <div class="flex items-center space-x-4">
215
+ <button id="save-btn" class="px-4 py-2 bg-gray-700 hover:bg-gray-600 rounded-lg transition">
216
+ <i class="fas fa-save mr-2"></i> Save Design
217
+ </button>
218
+ <button id="share-btn" class="px-4 py-2 bg-blue-600 hover:bg-blue-500 rounded-lg transition">
219
+ <i class="fas fa-share-alt mr-2"></i> Share
220
+ </button>
221
+ </div>
222
+ </header>
223
+
224
+ <!-- Progress Bar -->
225
+ <div class="mb-8">
226
+ <div class="flex justify-between mb-2">
227
+ <span>Customization Progress</span>
228
+ <span id="progress-percent">0%</span>
229
+ </div>
230
+ <div class="w-full bg-gray-700 rounded-full h-2.5">
231
+ <div id="progress-bar" class="progress-bar h-2.5 rounded-full" style="width: 0%"></div>
232
+ </div>
233
+ </div>
234
+
235
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
236
+ <!-- Left Panel - Car Selection & Color Picker -->
237
+ <div class="lg:col-span-1 bg-gray-800 rounded-xl p-6">
238
+ <h2 class="text-xl font-bold mb-4 flex items-center">
239
+ <i class="fas fa-car mr-2 text-orange-500"></i> Car Model
240
+ </h2>
241
+
242
+ <div class="grid grid-cols-2 gap-4 mb-8">
243
+ <div class="car-option bg-gray-700 p-4 rounded-lg cursor-pointer transition hover:bg-gray-600" data-model="muscle">
244
+ <img src="https://cdn-icons-png.flaticon.com/512/744/744465.png" alt="Muscle Car" class="w-full h-24 object-contain">
245
+ <p class="text-center mt-2">Muscle Car</p>
246
+ </div>
247
+ <div class="car-option bg-gray-700 p-4 rounded-lg cursor-pointer transition hover:bg-gray-600" data-model="pickup">
248
+ <img src="https://cdn-icons-png.flaticon.com/512/3665/3665182.png" alt="Vintage Pickup" class="w-full h-24 object-contain">
249
+ <p class="text-center mt-2">Vintage Pickup</p>
250
+ </div>
251
+ <div class="car-option bg-gray-700 p-4 rounded-lg cursor-pointer transition hover:bg-gray-600" data-model="rally">
252
+ <img src="https://cdn-icons-png.flaticon.com/512/3665/3665185.png" alt="Rally Car" class="w-full h-24 object-contain">
253
+ <p class="text-center mt-2">Rally Car</p>
254
+ </div>
255
+ <div class="car-option bg-gray-700 p-4 rounded-lg cursor-pointer transition hover:bg-gray-600" data-model="sports">
256
+ <img src="https://cdn-icons-png.flaticon.com/512/3079/3079019.png" alt="Sports Car" class="w-full h-24 object-contain">
257
+ <p class="text-center mt-2">Sports Car</p>
258
+ </div>
259
+ </div>
260
+
261
+ <h2 class="text-xl font-bold mb-4 flex items-center">
262
+ <i class="fas fa-palette mr-2 text-cyan-400"></i> Paint Color
263
+ </h2>
264
+
265
+ <div class="grid grid-cols-5 gap-3 mb-6">
266
+ <div class="color-option selected" style="background-color: #ff3e00;" data-color="#ff3e00"></div>
267
+ <div class="color-option" style="background-color: #00c4cc;" data-color="#00c4cc"></div>
268
+ <div class="color-option" style="background-color: #9c27b0;" data-color="#9c27b0"></div>
269
+ <div class="color-option" style="background-color: #4caf50;" data-color="#4caf50"></div>
270
+ <div class="color-option" style="background-color: #2196f3;" data-color="#2196f3"></div>
271
+ <div class="color-option" style="background-color: #ffeb3b;" data-color="#ffeb3b"></div>
272
+ <div class="color-option" style="background-color: #795548;" data-color="#795548"></div>
273
+ <div class="color-option" style="background-color: #607d8b;" data-color="#607d8b"></div>
274
+ <div class="color-option" style="background-color: #000000;" data-color="#000000"></div>
275
+ <div class="color-option" style="background-color: #ffffff;" data-color="#ffffff"></div>
276
+ </div>
277
+
278
+ <button id="magic-color-btn" class="w-full py-3 bg-gradient-to-r from-purple-500 to-pink-500 rounded-lg font-bold mb-6 hover:scale-105 transition flex items-center justify-center">
279
+ <i class="fas fa-magic mr-2"></i> MAGIC COLOR
280
+ </button>
281
+
282
+ <h2 class="text-xl font-bold mb-4 flex items-center">
283
+ <i class="fas fa-spray-can mr-2 text-yellow-400"></i> Special Effects
284
+ </h2>
285
+
286
+ <div class="grid grid-cols-2 gap-3">
287
+ <button class="effect-btn py-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition" data-effect="metallic">
288
+ <i class="fas fa-gem mr-1"></i> Metallic
289
+ </button>
290
+ <button class="effect-btn py-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition" data-effect="pearlescent">
291
+ <i class="fas fa-feather-alt mr-1"></i> Pearlescent
292
+ </button>
293
+ <button class="effect-btn py-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition" data-effect="matte">
294
+ <i class="fas fa-texture mr-1"></i> Matte
295
+ </button>
296
+ <button class="effect-btn py-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition" data-effect="glow">
297
+ <i class="fas fa-lightbulb mr-1"></i> Neon Glow
298
+ </button>
299
+ </div>
300
+ </div>
301
+
302
+ <!-- Center Panel - 3D Car Viewer -->
303
+ <div class="lg:col-span-1">
304
+ <div id="webgl-container">
305
+ <div id="car-viewer" class="w-full h-full flex items-center justify-center">
306
+ <div class="text-center">
307
+ <i class="fas fa-car text-6xl text-gray-500 mb-4"></i>
308
+ <p class="text-gray-400">Select a car model to begin customization</p>
309
+ </div>
310
+ </div>
311
+ <div id="paint-effect" class="paint-effect"></div>
312
+ </div>
313
+
314
+ <div class="flex justify-center mt-4 space-x-4">
315
+ <button id="rotate-left" class="p-3 bg-gray-800 rounded-full hover:bg-gray-700 transition">
316
+ <i class="fas fa-undo-alt"></i>
317
+ </button>
318
+ <button id="reset-view" class="p-3 bg-gray-800 rounded-full hover:bg-gray-700 transition">
319
+ <i class="fas fa-redo"></i>
320
+ </button>
321
+ <button id="rotate-right" class="p-3 bg-gray-800 rounded-full hover:bg-gray-700 transition">
322
+ <i class="fas fa-redo-alt"></i>
323
+ </button>
324
+ </div>
325
+ </div>
326
+
327
+ <!-- Right Panel - Sticker Customization -->
328
+ <div class="lg:col-span-1 bg-gray-800 rounded-xl p-6">
329
+ <h2 class="text-xl font-bold mb-4 flex items-center">
330
+ <i class="fas fa-sticky-note mr-2 text-yellow-400"></i> Stickers & Decals
331
+ </h2>
332
+
333
+ <div class="flex space-x-2 mb-4 overflow-x-auto pb-2">
334
+ <button class="sticker-category px-4 py-2 bg-gray-700 rounded-lg active" data-category="all">
335
+ All
336
+ </button>
337
+ <button class="sticker-category px-4 py-2 bg-gray-700 rounded-lg" data-category="flames">
338
+ Flames
339
+ </button>
340
+ <button class="sticker-category px-4 py-2 bg-gray-700 rounded-lg" data-category="logos">
341
+ Logos
342
+ </button>
343
+ <button class="sticker-category px-4 py-2 bg-gray-700 rounded-lg" data-category="racing">
344
+ Racing
345
+ </button>
346
+ <button class="sticker-category px-4 py-2 bg-gray-700 rounded-lg" data-category="funny">
347
+ Funny
348
+ </button>
349
+ </div>
350
+
351
+ <div class="mb-4 relative">
352
+ <input type="text" id="sticker-search" placeholder="Search stickers..." class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500">
353
+ <i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
354
+ </div>
355
+
356
+ <div id="sticker-grid" class="grid grid-cols-3 gap-3 h-64 overflow-y-auto">
357
+ <!-- Stickers will be loaded here -->
358
+ </div>
359
+
360
+ <div class="mt-6">
361
+ <h3 class="font-bold mb-2">Selected Stickers</h3>
362
+ <div id="selected-stickers" class="bg-gray-700 rounded-lg p-3 min-h-20">
363
+ <p class="text-gray-400 text-sm">Drag stickers onto the car to place them</p>
364
+ </div>
365
+ </div>
366
+
367
+ <div class="mt-6">
368
+ <h3 class="font-bold mb-2">Sticker Options</h3>
369
+ <div class="grid grid-cols-2 gap-2">
370
+ <button id="resize-sticker" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
371
+ <i class="fas fa-expand-alt mr-1"></i> Resize
372
+ </button>
373
+ <button id="rotate-sticker" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
374
+ <i class="fas fa-sync-alt mr-1"></i> Rotate
375
+ </button>
376
+ <button id="flip-sticker" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
377
+ <i class="fas fa-exchange-alt mr-1"></i> Flip
378
+ </button>
379
+ <button id="remove-sticker" class="p-2 bg-gray-700 rounded-lg hover:bg-gray-600 transition">
380
+ <i class="fas fa-trash-alt mr-1"></i> Remove
381
+ </button>
382
+ </div>
383
+ </div>
384
+ </div>
385
+ </div>
386
+
387
+ <!-- Order Summary Panel -->
388
+ <div id="order-panel" class="mt-8 bg-gray-800 rounded-xl p-6">
389
+ <h2 class="text-xl font-bold mb-4 flex items-center">
390
+ <i class="fas fa-receipt mr-2 text-green-400"></i> Order Summary
391
+ </h2>
392
+
393
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
394
+ <div class="bg-gray-700 rounded-lg p-4">
395
+ <h3 class="font-bold mb-2 text-orange-400">Car Details</h3>
396
+ <div id="car-details">
397
+ <p>Model: <span id="car-model-display">Not selected</span></p>
398
+ <p>Color: <span id="car-color-display">Not selected</span></p>
399
+ <p>Effects: <span id="car-effects-display">None</span></p>
400
+ </div>
401
+ </div>
402
+
403
+ <div class="bg-gray-700 rounded-lg p-4">
404
+ <h3 class="font-bold mb-2 text-cyan-400">Stickers Applied</h3>
405
+ <div id="stickers-list">
406
+ <p class="text-gray-400">No stickers added yet</p>
407
+ </div>
408
+ </div>
409
+
410
+ <div class="bg-gray-700 rounded-lg p-4">
411
+ <h3 class="font-bold mb-2 text-green-400">Pricing</h3>
412
+ <div id="price-breakdown">
413
+ <div class="flex justify-between mb-1">
414
+ <span>Base Price:</span>
415
+ <span>$0.00</span>
416
+ </div>
417
+ <div class="flex justify-between mb-1">
418
+ <span>Stickers:</span>
419
+ <span>$0.00</span>
420
+ </div>
421
+ <div class="flex justify-between mb-1">
422
+ <span>Effects:</span>
423
+ <span>$0.00</span>
424
+ </div>
425
+ <div class="border-t border-gray-600 my-2"></div>
426
+ <div class="flex justify-between font-bold text-lg">
427
+ <span>Total:</span>
428
+ <span>$0.00</span>
429
+ </div>
430
+ </div>
431
+
432
+ <button id="checkout-btn" class="w-full mt-4 py-3 bg-gradient-to-r from-green-500 to-blue-500 rounded-lg font-bold hover:scale-105 transition disabled:opacity-50 disabled:cursor-not-allowed" disabled>
433
+ PROCEED TO CHECKOUT <i class="fas fa-arrow-right ml-2"></i>
434
+ </button>
435
+ </div>
436
+ </div>
437
+ </div>
438
+ </div>
439
+
440
+ <!-- Checkout Modal -->
441
+ <div id="checkout-modal" class="fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50 hidden">
442
+ <div class="bg-gray-800 rounded-xl p-8 max-w-2xl w-full mx-4 max-h-[90vh] overflow-y-auto">
443
+ <div class="flex justify-between items-center mb-6">
444
+ <h2 class="text-2xl font-bold text-green-400">
445
+ <i class="fas fa-shopping-cart mr-2"></i> Complete Your Order
446
+ </h2>
447
+ <button id="close-checkout" class="text-gray-400 hover:text-white">
448
+ <i class="fas fa-times text-2xl"></i>
449
+ </button>
450
+ </div>
451
+
452
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
453
+ <div>
454
+ <h3 class="font-bold mb-4 text-orange-400">Your Design</h3>
455
+ <div id="checkout-car-preview" class="bg-gray-700 rounded-lg p-4 h-64 flex items-center justify-center">
456
+ <i class="fas fa-car text-4xl text-gray-500"></i>
457
+ </div>
458
+ </div>
459
+
460
+ <div>
461
+ <h3 class="font-bold mb-4 text-cyan-400">Order Details</h3>
462
+ <div id="checkout-summary" class="mb-6">
463
+ <!-- Order summary will be populated here -->
464
+ </div>
465
+
466
+ <h3 class="font-bold mb-4 text-green-400">Shipping Information</h3>
467
+ <form id="checkout-form" class="space-y-4">
468
+ <div>
469
+ <label class="block text-sm font-medium mb-1">Full Name</label>
470
+ <input type="text" required class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500">
471
+ </div>
472
+ <div>
473
+ <label class="block text-sm font-medium mb-1">Email</label>
474
+ <input type="email" required class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500">
475
+ </div>
476
+ <div>
477
+ <label class="block text-sm font-medium mb-1">Address</label>
478
+ <input type="text" required class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500">
479
+ </div>
480
+ <div class="grid grid-cols-2 gap-4">
481
+ <div>
482
+ <label class="block text-sm font-medium mb-1">City</label>
483
+ <input type="text" required class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500">
484
+ </div>
485
+ <div>
486
+ <label class="block text-sm font-medium mb-1">ZIP Code</label>
487
+ <input type="text" required class="w-full px-4 py-2 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500">
488
+ </div>
489
+ </div>
490
+
491
+ <div class="pt-4">
492
+ <button type="submit" class="w-full py-3 bg-gradient-to-r from-green-500 to-blue-500 rounded-lg font-bold hover:scale-105 transition">
493
+ PLACE ORDER <i class="fas fa-check-circle ml-2"></i>
494
+ </button>
495
+ </div>
496
+ </form>
497
+ </div>
498
+ </div>
499
+ </div>
500
+ </div>
501
+
502
+ <!-- Success Modal -->
503
+ <div id="success-modal" class="fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center z-50 hidden">
504
+ <div class="bg-gray-800 rounded-xl p-8 max-w-md text-center">
505
+ <div class="text-green-400 text-6xl mb-4">
506
+ <i class="fas fa-check-circle"></i>
507
+ </div>
508
+ <h2 class="text-2xl font-bold mb-2">Order Placed Successfully!</h2>
509
+ <p class="text-gray-300 mb-6">Thank you for your purchase. Your custom car design is on its way!</p>
510
+ <button id="success-close" class="px-6 py-2 bg-orange-500 rounded-lg font-bold hover:bg-orange-600 transition">
511
+ CLOSE
512
+ </button>
513
+ </div>
514
+ </div>
515
+
516
+ <!-- Tooltip -->
517
+ <div id="tooltip" class="tooltip"></div>
518
+
519
+ <script>
520
+ document.addEventListener('DOMContentLoaded', function() {
521
+ // Sample sticker data
522
+ const stickers = [
523
+ { id: 1, name: "Flame 1", category: "flames", price: 5.99, svg: '<svg viewBox="0 0 100 100"><path d="M20,80 Q40,20 60,80 Q80,10 90,50" stroke="#ff3e00" stroke-width="8" fill="none"/></svg>' },
524
+ { id: 2, name: "Flame 2", category: "flames", price: 6.99, svg: '<svg viewBox="0 0 100 100"><path d="M10,70 Q30,10 50,70 Q70,0 90,40" stroke="#ff9900" stroke-width="8" fill="none"/></svg>' },
525
+ { id: 3, name: "Racing Stripe", category: "racing", price: 12.99, svg: '<svg viewBox="0 0 100 100"><rect x="20" y="30" width="60" height="40" fill="#ffffff"/></svg>' },
526
+ { id: 4, name: "Speed", category: "racing", price: 8.99, svg: '<svg viewBox="0 0 100 100"><text x="50" y="60" font-family="Arial" font-size="40" text-anchor="middle" fill="#ffffff">SPEED</text></svg>' },
527
+ { id: 5, name: "Logo 1", category: "logos", price: 9.99, svg: '<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" stroke="#00c4cc" stroke-width="5" fill="none"/></svg>' },
528
+ { id: 6, name: "Logo 2", category: "logos", price: 7.99, svg: '<svg viewBox="0 0 100 100"><polygon points="50,10 80,90 20,90" stroke="#ffcc00" stroke-width="3" fill="none"/></svg>' },
529
+ { id: 7, name: "LOL", category: "funny", price: 4.99, svg: '<svg viewBox="0 0 100 100"><text x="50" y="60" font-family="Arial" font-size="40" text-anchor="middle" fill="#ffffff">LOL</text></svg>' },
530
+ { id: 8, name: "Zoom", category: "funny", price: 5.99, svg: '<svg viewBox="0 0 100 100"><text x="50" y="60" font-family="Arial" font-size="40" text-anchor="middle" fill="#ffffff">ZOOM</text></svg>' },
531
+ { id: 9, name: "Skull", category: "flames", price: 8.99, svg: '<svg viewBox="0 0 100 100"><circle cx="50" cy="40" r="25" fill="#ffffff"/><circle cx="40" cy="35" r="5" fill="#000000"/><circle cx="60" cy="35" r="5" fill="#000000"/><path d="M40,60 Q50,70 60,60" stroke="#000000" stroke-width="3" fill="none"/></svg>' }
532
+ ];
533
+
534
+ // App state
535
+ const state = {
536
+ selectedCar: null,
537
+ carColor: '#ff3e00',
538
+ carEffects: [],
539
+ selectedStickers: [],
540
+ activeSticker: null,
541
+ currentView: 'front',
542
+ price: {
543
+ base: 0,
544
+ stickers: 0,
545
+ effects: 0,
546
+ total: 0
547
+ }
548
+ };
549
+
550
+ // DOM elements
551
+ const introScreen = document.getElementById('intro-screen');
552
+ const appContainer = document.getElementById('app-container');
553
+ const startBtn = document.getElementById('start-btn');
554
+ const carOptions = document.querySelectorAll('.car-option');
555
+ const colorOptions = document.querySelectorAll('.color-option');
556
+ const magicColorBtn = document.getElementById('magic-color-btn');
557
+ const effectBtns = document.querySelectorAll('.effect-btn');
558
+ const stickerCategories = document.querySelectorAll('.sticker-category');
559
+ const stickerSearch = document.getElementById('sticker-search');
560
+ const stickerGrid = document.getElementById('sticker-grid');
561
+ const selectedStickers = document.getElementById('selected-stickers');
562
+ const carViewer = document.getElementById('car-viewer');
563
+ const paintEffect = document.getElementById('paint-effect');
564
+ const rotateLeftBtn = document.getElementById('rotate-left');
565
+ const rotateRightBtn = document.getElementById('rotate-right');
566
+ const resetViewBtn = document.getElementById('reset-view');
567
+ const resizeStickerBtn = document.getElementById('resize-sticker');
568
+ const rotateStickerBtn = document.getElementById('rotate-sticker');
569
+ const flipStickerBtn = document.getElementById('flip-sticker');
570
+ const removeStickerBtn = document.getElementById('remove-sticker');
571
+ const carModelDisplay = document.getElementById('car-model-display');
572
+ const carColorDisplay = document.getElementById('car-color-display');
573
+ const carEffectsDisplay = document.getElementById('car-effects-display');
574
+ const stickersList = document.getElementById('stickers-list');
575
+ const checkoutBtn = document.getElementById('checkout-btn');
576
+ const checkoutModal = document.getElementById('checkout-modal');
577
+ const closeCheckout = document.getElementById('close-checkout');
578
+ const checkoutCarPreview = document.getElementById('checkout-car-preview');
579
+ const checkoutSummary = document.getElementById('checkout-summary');
580
+ const checkoutForm = document.getElementById('checkout-form');
581
+ const successModal = document.getElementById('success-modal');
582
+ const successClose = document.getElementById('success-close');
583
+ const progressBar = document.getElementById('progress-bar');
584
+ const progressPercent = document.getElementById('progress-percent');
585
+ const tooltip = document.getElementById('tooltip');
586
+
587
+ // Initialize the app
588
+ function init() {
589
+ // Load stickers
590
+ renderStickers();
591
+
592
+ // Set up event listeners
593
+ setupEventListeners();
594
+ }
595
+
596
+ // Set up all event listeners
597
+ function setupEventListeners() {
598
+ // Start button
599
+ startBtn.addEventListener('click', () => {
600
+ introScreen.style.opacity = '0';
601
+ introScreen.style.pointerEvents = 'none';
602
+ appContainer.classList.remove('hidden');
603
+
604
+ // Trigger confetti effect
605
+ createConfetti();
606
+ });
607
+
608
+ // Car selection
609
+ carOptions.forEach(option => {
610
+ option.addEventListener('click', () => {
611
+ const model = option.dataset.model;
612
+ selectCar(model);
613
+ });
614
+ });
615
+
616
+ // Color selection
617
+ colorOptions.forEach(option => {
618
+ option.addEventListener('click', () => {
619
+ const color = option.dataset.color;
620
+ selectColor(color);
621
+ });
622
+ });
623
+
624
+ // Magic color button
625
+ magicColorBtn.addEventListener('click', () => {
626
+ triggerMagicColorEffect();
627
+ });
628
+
629
+ // Effect buttons
630
+ effectBtns.forEach(btn => {
631
+ btn.addEventListener('click', () => {
632
+ const effect = btn.dataset.effect;
633
+ toggleEffect(effect);
634
+ });
635
+ });
636
+
637
+ // Sticker categories
638
+ stickerCategories.forEach(cat => {
639
+ cat.addEventListener('click', () => {
640
+ const category = cat.dataset.category;
641
+ filterStickers(category);
642
+
643
+ // Update active state
644
+ stickerCategories.forEach(c => c.classList.remove('active'));
645
+ cat.classList.add('active');
646
+ });
647
+ });
648
+
649
+ // Sticker search
650
+ stickerSearch.addEventListener('input', () => {
651
+ filterStickers();
652
+ });
653
+
654
+ // Car rotation controls
655
+ rotateLeftBtn.addEventListener('click', () => {
656
+ rotateCar('left');
657
+ });
658
+
659
+ rotateRightBtn.addEventListener('click', () => {
660
+ rotateCar('right');
661
+ });
662
+
663
+ resetViewBtn.addEventListener('click', () => {
664
+ resetCarView();
665
+ });
666
+
667
+ // Sticker manipulation buttons
668
+ resizeStickerBtn.addEventListener('click', () => {
669
+ if (state.activeSticker) {
670
+ resizeSticker(state.activeSticker);
671
+ }
672
+ });
673
+
674
+ rotateStickerBtn.addEventListener('click', () => {
675
+ if (state.activeSticker) {
676
+ rotateSticker(state.activeSticker);
677
+ }
678
+ });
679
+
680
+ flipStickerBtn.addEventListener('click', () => {
681
+ if (state.activeSticker) {
682
+ flipSticker(state.activeSticker);
683
+ }
684
+ });
685
+
686
+ removeStickerBtn.addEventListener('click', () => {
687
+ if (state.activeSticker) {
688
+ removeSticker(state.activeSticker);
689
+ }
690
+ });
691
+
692
+ // Checkout flow
693
+ checkoutBtn.addEventListener('click', () => {
694
+ openCheckoutModal();
695
+ });
696
+
697
+ closeCheckout.addEventListener('click', () => {
698
+ checkoutModal.classList.add('hidden');
699
+ });
700
+
701
+ checkoutForm.addEventListener('submit', (e) => {
702
+ e.preventDefault();
703
+ completeOrder();
704
+ });
705
+
706
+ successClose.addEventListener('click', () => {
707
+ successModal.classList.add('hidden');
708
+ });
709
+ }
710
+
711
+ // Render stickers in the grid
712
+ function renderStickers(filteredStickers = stickers) {
713
+ stickerGrid.innerHTML = '';
714
+
715
+ filteredStickers.forEach(sticker => {
716
+ const stickerElement = document.createElement('div');
717
+ stickerElement.className = 'sticker-preview p-2 bg-gray-700 rounded-lg cursor-pointer flex items-center justify-center';
718
+ stickerElement.innerHTML = sticker.svg;
719
+ stickerElement.dataset.id = sticker.id;
720
+ stickerElement.dataset.name = sticker.name;
721
+ stickerElement.dataset.price = sticker.price;
722
+
723
+ // Add tooltip
724
+ stickerElement.addEventListener('mouseenter', (e) => {
725
+ tooltip.textContent = `${sticker.name} - $${sticker.price}`;
726
+ tooltip.style.left = `${e.pageX}px`;
727
+ tooltip.style.top = `${e.pageY - 40}px`;
728
+ tooltip.style.opacity = '1';
729
+ });
730
+
731
+ stickerElement.addEventListener('mouseleave', () => {
732
+ tooltip.style.opacity = '0';
733
+ });
734
+
735
+ stickerElement.addEventListener('mousemove', (e) => {
736
+ tooltip.style.left = `${e.pageX}px`;
737
+ tooltip.style.top = `${e.pageY - 40}px`;
738
+ });
739
+
740
+ // Make sticker draggable
741
+ stickerElement.draggable = true;
742
+ stickerElement.addEventListener('dragstart', (e) => {
743
+ e.dataTransfer.setData('text/plain', JSON.stringify({
744
+ id: sticker.id,
745
+ name: sticker.name,
746
+ price: sticker.price,
747
+ svg: sticker.svg
748
+ }));
749
+ });
750
+
751
+ stickerGrid.appendChild(stickerElement);
752
+ });
753
+ }
754
+
755
+ // Filter stickers by category and search term
756
+ function filterStickers(category = 'all') {
757
+ const searchTerm = stickerSearch.value.toLowerCase();
758
+
759
+ const filtered = stickers.filter(sticker => {
760
+ const matchesCategory = category === 'all' || sticker.category === category;
761
+ const matchesSearch = sticker.name.toLowerCase().includes(searchTerm);
762
+ return matchesCategory && matchesSearch;
763
+ });
764
+
765
+ renderStickers(filtered);
766
+ }
767
+
768
+ // Select a car model
769
+ function selectCar(model) {
770
+ state.selectedCar = model;
771
+
772
+ // Update UI
773
+ carOptions.forEach(option => {
774
+ option.classList.remove('bg-orange-500');
775
+ if (option.dataset.model === model) {
776
+ option.classList.add('bg-orange-500');
777
+ }
778
+ });
779
+
780
+ // Update car display
781
+ updateCarDisplay();
782
+
783
+ // Update price
784
+ updatePrice();
785
+
786
+ // Update progress
787
+ updateProgress();
788
+ }
789
+
790
+ // Select a color
791
+ function selectColor(color) {
792
+ state.carColor = color;
793
+
794
+ // Update UI
795
+ colorOptions.forEach(option => {
796
+ option.classList.remove('selected');
797
+ if (option.dataset.color === color) {
798
+ option.classList.add('selected');
799
+ }
800
+ });
801
+
802
+ // Update car display
803
+ updateCarDisplay();
804
+
805
+ // Trigger paint effect
806
+ triggerPaintEffect();
807
+
808
+ // Update progress
809
+ updateProgress();
810
+ }
811
+
812
+ // Toggle a special effect
813
+ function toggleEffect(effect) {
814
+ const index = state.carEffects.indexOf(effect);
815
+ if (index === -1) {
816
+ state.carEffects.push(effect);
817
+ } else {
818
+ state.carEffects.splice(index, 1);
819
+ }
820
+
821
+ // Update UI
822
+ effectBtns.forEach(btn => {
823
+ if (btn.dataset.effect === effect) {
824
+ btn.classList.toggle('bg-orange-500');
825
+ }
826
+ });
827
+
828
+ // Update car display
829
+ updateCarDisplay();
830
+
831
+ // Update price
832
+ updatePrice();
833
+
834
+ // Update progress
835
+ updateProgress();
836
+ }
837
+
838
+ // Trigger the magic color effect
839
+ function triggerMagicColorEffect() {
840
+ // Get random color
841
+ const colors = Array.from(colorOptions).map(opt => opt.dataset.color);
842
+ const randomColor = colors[Math.floor(Math.random() * colors.length)];
843
+
844
+ // Select the color
845
+ selectColor(randomColor);
846
+
847
+ // Add special animation
848
+ paintEffect.style.opacity = '1';
849
+ paintEffect.style.animation = 'none';
850
+ void paintEffect.offsetWidth; // Trigger reflow
851
+ paintEffect.style.animation = 'paintEffect 2s forwards';
852
+
853
+ // Play sound (simulated)
854
+ playSoundEffect('spray');
855
+ }
856
+
857
+ // Trigger paint effect
858
+ function triggerPaintEffect() {
859
+ paintEffect.style.opacity = '1';
860
+ paintEffect.style.animation = 'none';
861
+ void paintEffect.offsetWidth; // Trigger reflow
862
+ paintEffect.style.animation = 'paintEffect 1s forwards';
863
+
864
+ // Play sound (simulated)
865
+ playSoundEffect('spray');
866
+ }
867
+
868
+ // Rotate car view
869
+ function rotateCar(direction) {
870
+ const views = ['front', 'left', 'back', 'right'];
871
+ let currentIndex = views.indexOf(state.currentView);
872
+
873
+ if (direction === 'left') {
874
+ currentIndex = (currentIndex - 1 + views.length) % views.length;
875
+ } else {
876
+ currentIndex = (currentIndex + 1) % views.length;
877
+ }
878
+
879
+ state.currentView = views[currentIndex];
880
+ updateCarDisplay();
881
+ }
882
+
883
+ // Reset car view
884
+ function resetCarView() {
885
+ state.currentView = 'front';
886
+ updateCarDisplay();
887
+ }
888
+
889
+ // Update car display
890
+ function updateCarDisplay() {
891
+ if (!state.selectedCar) {
892
+ carViewer.innerHTML = `
893
+ <div class="text-center">
894
+ <i class="fas fa-car text-6xl text-gray-500 mb-4"></i>
895
+ <p class="text-gray-400">Select a car model to begin customization</p>
896
+ </div>
897
+ `;
898
+ return;
899
+ }
900
+
901
+ // In a real app, this would use Three.js to render the 3D model
902
+ // For this demo, we'll use a simplified representation
903
+
904
+ let carHtml = '';
905
+ const colorStyle = `background-color: ${state.carColor};`;
906
+ let effectStyle = '';
907
+
908
+ if (state.carEffects.includes('metallic')) {
909
+ effectStyle += 'background: linear-gradient(135deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0.3) 100%);';
910
+ }
911
+
912
+ if (state.carEffects.includes('pearlescent')) {
913
+ effectStyle += 'background: linear-gradient(45deg, rgba(255,255,255,0.1) 0%, rgba(255,0,255,0.1) 50%, rgba(0,255,255,0.1) 100%);';
914
+ }
915
+
916
+ if (state.carEffects.includes('matte')) {
917
+ effectStyle += 'filter: saturate(0.7);';
918
+ }
919
+
920
+ if (state.carEffects.includes('glow')) {
921
+ effectStyle += 'box-shadow: 0 0 20px rgba(0, 255, 255, 0.7);';
922
+ }
923
+
924
+ // Different views
925
+ if (state.currentView === 'front') {
926
+ carHtml = `
927
+ <div class="relative w-64 h-32 mx-auto">
928
+ <div class="absolute top-0 left-0 w-full h-full" style="${colorStyle} ${effectStyle} border-radius: 20px 20px 0 0;">
929
+ <div class="absolute top-1/4 left-1/4 w-1/2 h-1/4 bg-black opacity-20 rounded-full"></div>
930
+ <div class="absolute top-1/4 right-1/4 w-1/2 h-1/4 bg-black opacity-20 rounded-full"></div>
931
+ </div>
932
+ <div class="absolute bottom-0 left-0 w-full h-1/4 bg-gray-800 rounded-b-lg"></div>
933
+ ${renderStickersOnCar()}
934
+ </div>
935
+ `;
936
+ } else if (state.currentView === 'left') {
937
+ carHtml = `
938
+ <div class="relative w-64 h-32 mx-auto">
939
+ <div class="absolute top-0 left-0 w-full h-full" style="${colorStyle} ${effectStyle} border-radius: 20px 0 0 20px;">
940
+ <div class="absolute top-1/4 left-1/4 w-1/4 h-1/4 bg-black opacity-20 rounded-full"></div>
941
+ </div>
942
+ <div class="absolute bottom-0 left-0 w-full h-1/4 bg-gray-800 rounded-r-lg"></div>
943
+ ${renderStickersOnCar()}
944
+ </div>
945
+ `;
946
+ } else if (state.currentView === 'back') {
947
+ carHtml = `
948
+ <div class="relative w-64 h-32 mx-auto">
949
+ <div class="absolute top-0 left-0 w-full h-full" style="${colorStyle} ${effectStyle} border-radius: 0 0 20px 20px;">
950
+ <div class="absolute bottom-1/4 left-1/4 w-1/2 h-1/4 bg-black opacity-20 rounded-full"></div>
951
+ </div>
952
+ <div class="absolute bottom-0 left-0 w-full h-1/4 bg-gray-800 rounded-t-lg"></div>
953
+ ${renderStickersOnCar()}
954
+ </div>
955
+ `;
956
+ } else if (state.currentView === 'right') {
957
+ carHtml = `
958
+ <div class="relative w-64 h-32 mx-auto">
959
+ <div class="absolute top-0 left-0 w-full h-full" style="${colorStyle} ${effectStyle} border-radius: 0 20px 20px 0;">
960
+ <div class="absolute top-1/4 right-1/4 w-1/4 h-1/4 bg-black opacity-20 rounded-full"></div>
961
+ </div>
962
+ <div class="absolute bottom-0 left-0 w-full h-1/4 bg-gray-800 rounded-l-lg"></div>
963
+ ${renderStickersOnCar()}
964
+ </div>
965
+ `;
966
+ }
967
+
968
+ carViewer.innerHTML = carHtml;
969
+
970
+ // Make car a drop target for stickers
971
+ carViewer.addEventListener('dragover', (e) => {
972
+ e.preventDefault();
973
+ });
974
+
975
+ carViewer.addEventListener('drop', (e) => {
976
+ e.preventDefault();
977
+ const data = JSON.parse(e.dataTransfer.getData('text/plain'));
978
+ addStickerToCar(data);
979
+ });
980
+
981
+ // Update order summary
982
+ updateOrderSummary();
983
+ }
984
+
985
+ // Render stickers on the car
986
+ function renderStickersOnCar() {
987
+ let html = '';
988
+ state.selectedStickers.forEach(sticker => {
989
+ // In a real app, this would position the sticker on the 3D model
990
+ // For this demo, we'll just show them floating
991
+ const style = `
992
+ position: absolute;
993
+ left: ${Math.random() * 60 + 20}%;
994
+ top: ${Math.random() * 60 + 20}%;
995
+ transform: rotate(${Math.random() * 30 - 15}deg);
996
+ width: 30%;
997
+ height: auto;
998
+ `;
999
+
1000
+ html += `
1001
+ <div class="sticker-on-car" style="${style}" data-id="${sticker.id}">
1002
+ ${sticker.svg}
1003
+ </div>
1004
+ `;
1005
+ });
1006
+ return html;
1007
+ }
1008
+
1009
+ // Add sticker to car
1010
+ function addStickerToCar(stickerData) {
1011
+ // Check if sticker is already added
1012
+ const exists = state.selectedStickers.some(s => s.id === stickerData.id);
1013
+ if (exists) {
1014
+ // Show error feedback
1015
+ const stickerElement = document.querySelector(`.sticker-preview[data-id="${stickerData.id}"]`);
1016
+ stickerElement.classList.add('invalid-placement');
1017
+ setTimeout(() => {
1018
+ stickerElement.classList.remove('invalid-placement');
1019
+ }, 500);
1020
+
1021
+ // Play error sound
1022
+ playSoundEffect('error');
1023
+ return;
1024
+ }
1025
+
1026
+ // Add to selected stickers
1027
+ state.selectedStickers.push(stickerData);
1028
+
1029
+ // Update car display
1030
+ updateCarDisplay();
1031
+
1032
+ // Update selected stickers list
1033
+ updateSelectedStickersList();
1034
+
1035
+ // Update price
1036
+ updatePrice();
1037
+
1038
+ // Update progress
1039
+ updateProgress();
1040
+
1041
+ // Play success sound
1042
+ playSoundEffect('success');
1043
+
1044
+ // Trigger particle effect (simulated)
1045
+ triggerStickerEffect();
1046
+ }
1047
+
1048
+ // Resize sticker
1049
+ function resizeSticker(sticker) {
1050
+ // In a real app, this would resize the sticker on the 3D model
1051
+ alert(`Resizing sticker: ${sticker.name}`);
1052
+ }
1053
+
1054
+ // Rotate sticker
1055
+ function rotateSticker(sticker) {
1056
+ // In a real app, this would rotate the sticker on the 3D model
1057
+ alert(`Rotating sticker: ${sticker.name}`);
1058
+ }
1059
+
1060
+ // Flip sticker
1061
+ function flipSticker(sticker) {
1062
+ // In a real app, this would flip the sticker on the 3D model
1063
+ alert(`Flipping sticker: ${sticker.name}`);
1064
+ }
1065
+
1066
+ // Remove sticker
1067
+ function removeSticker(sticker) {
1068
+ // Remove from selected stickers
1069
+ state.selectedStickers = state.selectedStickers.filter(s => s.id !== sticker.id);
1070
+
1071
+ // Update car display
1072
+ updateCarDisplay();
1073
+
1074
+ // Update selected stickers list
1075
+ updateSelectedStickersList();
1076
+
1077
+ // Update price
1078
+ updatePrice();
1079
+
1080
+ // Update progress
1081
+ updateProgress();
1082
+
1083
+ // Play sound
1084
+ playSoundEffect('remove');
1085
+ }
1086
+
1087
+ // Update selected stickers list
1088
+ function updateSelectedStickersList() {
1089
+ if (state.selectedStickers.length === 0) {
1090
+ selectedStickers.innerHTML = '<p class="text-gray-400 text-sm">Drag stickers onto the car to place them</p>';
1091
+ return;
1092
+ }
1093
+
1094
+ let html = '<div class="grid grid-cols-2 gap-2">';
1095
+ state.selectedStickers.forEach(sticker => {
1096
+ html += `
1097
+ <div class="p-2 bg-gray-600 rounded-lg flex items-center justify-between" data-id="${sticker.id}">
1098
+ <div class="w-8 h-8">${sticker.svg}</div>
1099
+ <span class="text-sm">${sticker.name}</span>
1100
+ <button class="text-red-400 hover:text-red-300" onclick="removeStickerById(${sticker.id})">
1101
+ <i class="fas fa-times"></i>
1102
+ </button>
1103
+ </div>
1104
+ `;
1105
+ });
1106
+ html += '</div>';
1107
+
1108
+ selectedStickers.innerHTML = html;
1109
+ }
1110
+
1111
+ // Update price breakdown
1112
+ function updatePrice() {
1113
+ // Base price based on car model
1114
+ let basePrice = 0;
1115
+ if (state.selectedCar === 'muscle') basePrice = 29900;
1116
+ else if (state.selectedCar === 'pickup') basePrice = 24900;
1117
+ else if (state.selectedCar === 'rally') basePrice = 34900;
1118
+ else if (state.selectedCar === 'sports') basePrice = 45900;
1119
+
1120
+ // Stickers price
1121
+ const stickersPrice = state.selectedStickers.reduce((sum, sticker) => sum + sticker.price, 0);
1122
+
1123
+ // Effects price
1124
+ const effectsPrice = state.carEffects.length * 500;
1125
+
1126
+ // Total price
1127
+ const totalPrice = basePrice + stickersPrice + effectsPrice;
1128
+
1129
+ // Update state
1130
+ state.price = {
1131
+ base: basePrice,
1132
+ stickers: stickersPrice,
1133
+ effects: effectsPrice,
1134
+ total: totalPrice
1135
+ };
1136
+
1137
+ // Update UI
1138
+ const priceBreakdown = document.getElementById('price-breakdown');
1139
+ priceBreakdown.innerHTML = `
1140
+ <div class="flex justify-between mb-1">
1141
+ <span>Base Price:</span>
1142
+ <span>$${(basePrice / 100).toFixed(2)}</span>
1143
+ </div>
1144
+ <div class="flex justify-between mb-1">
1145
+ <span>Stickers:</span>
1146
+ <span>$${(stickersPrice / 100).toFixed(2)}</span>
1147
+ </div>
1148
+ <div class="flex justify-between mb-1">
1149
+ <span>Effects:</span>
1150
+ <span>$${(effectsPrice / 100).toFixed(2)}</span>
1151
+ </div>
1152
+ <div class="border-t border-gray-600 my-2"></div>
1153
+ <div class="flex justify-between font-bold text-lg">
1154
+ <span>Total:</span>
1155
+ <span>$${(totalPrice / 100).toFixed(2)}</span>
1156
+ </div>
1157
+ `;
1158
+
1159
+ // Enable/disable checkout button
1160
+ checkoutBtn.disabled = state.selectedCar === null || state.price.total === 0;
1161
+ }
1162
+
1163
+ // Update order summary
1164
+ function updateOrderSummary() {
1165
+ // Car details
1166
+ if (state.selectedCar) {
1167
+ const carName = state.selectedCar.charAt(0).toUpperCase() + state.selectedCar.slice(1);
1168
+ carModelDisplay.textContent = carName + ' Car';
1169
+ } else {
1170
+ carModelDisplay.textContent = 'Not selected';
1171
+ }
1172
+
1173
+ carColorDisplay.textContent = state.carColor || 'Not selected';
1174
+ carColorDisplay.style.color = state.carColor || 'inherit';
1175
+
1176
+ if (state.carEffects.length > 0) {
1177
+ carEffectsDisplay.textContent = state.carEffects.map(e =>
1178
+ e.charAt(0).toUpperCase() + e.slice(1)
1179
+ ).join(', ');
1180
+ } else {
1181
+ carEffectsDisplay.textContent = 'None';
1182
+ }
1183
+
1184
+ // Stickers list
1185
+ if (state.selectedStickers.length > 0) {
1186
+ let html = '<div class="space-y-2">';
1187
+ state.selectedStickers.forEach(sticker => {
1188
+ html += `
1189
+ <div class="flex justify-between items-center">
1190
+ <div class="flex items-center">
1191
+ <div class="w-6 h-6 mr-2">${sticker.svg}</div>
1192
+ <span>${sticker.name}</span>
1193
+ </div>
1194
+ <span>$${(sticker.price / 100).toFixed(2)}</span>
1195
+ </div>
1196
+ `;
1197
+ });
1198
+ html += '</div>';
1199
+ stickersList.innerHTML = html;
1200
+ } else {
1201
+ stickersList.innerHTML = '<p class="text-gray-400">No stickers added yet</p>';
1202
+ }
1203
+ }
1204
+
1205
+ // Update progress
1206
+ function updateProgress() {
1207
+ let progress = 0;
1208
+
1209
+ // Car selected: 30%
1210
+ if (state.selectedCar) progress += 30;
1211
+
1212
+ // Color selected: 20%
1213
+ if (state.carColor) progress += 20;
1214
+
1215
+ // At least one sticker: 30%
1216
+ if (state.selectedStickers.length > 0) progress += 30;
1217
+
1218
+ // Effects: 20% (max)
1219
+ progress += Math.min(state.carEffects.length * 5, 20);
1220
+
1221
+ // Update UI
1222
+ progressBar.style.width = `${progress}%`;
1223
+ progressPercent.textContent = `${progress}%`;
1224
+ }
1225
+
1226
+ // Open checkout modal
1227
+ function openCheckoutModal() {
1228
+ // Update preview
1229
+ checkoutCarPreview.innerHTML = '';
1230
+ const carPreview = carViewer.cloneNode(true);
1231
+ carPreview.classList.remove('relative');
1232
+ carPreview.classList.add('w-full', 'h-full');
1233
+ checkoutCarPreview.appendChild(carPreview);
1234
+
1235
+ // Update summary
1236
+ checkoutSummary.innerHTML = `
1237
+ <div class="space-y-2">
1238
+ <div class="flex justify-between">
1239
+ <span>Car Model:</span>
1240
+ <span>${carModelDisplay.textContent}</span>
1241
+ </div>
1242
+ <div class="flex justify-between">
1243
+ <span>Color:</span>
1244
+ <span style="color: ${state.carColor}">${state.carColor}</span>
1245
+ </div>
1246
+ <div class="flex justify-between">
1247
+ <span>Effects:</span>
1248
+ <span>${carEffectsDisplay.textContent}</span>
1249
+ </div>
1250
+ <div class="border-t border-gray-600 my-2"></div>
1251
+ ${stickersList.innerHTML}
1252
+ <div class="border-t border-gray-600 my-2"></div>
1253
+ <div class="flex justify-between font-bold">
1254
+ <span>Total:</span>
1255
+ <span>$${(state.price.total / 100).toFixed(2)}</span>
1256
+ </div>
1257
+ </div>
1258
+ `;
1259
+
1260
+ // Show modal
1261
+ checkoutModal.classList.remove('hidden');
1262
+ }
1263
+
1264
+ // Complete order
1265
+ function completeOrder() {
1266
+ // In a real app, this would process the payment
1267
+
1268
+ // Close checkout modal
1269
+ checkoutModal.classList.add('hidden');
1270
+
1271
+ // Show success modal
1272
+ successModal.classList.remove('hidden');
1273
+
1274
+ // Trigger confetti
1275
+ createConfetti();
1276
+
1277
+ // Play success sound
1278
+ playSoundEffect('success');
1279
+ }
1280
+
1281
+ // Trigger sticker placement effect
1282
+ function triggerStickerEffect() {
1283
+ // In a real app, this would show particles/sparkles
1284
+ // For this demo, we'll just show a simple animation
1285
+ const effect = document.createElement('div');
1286
+ effect.className = 'absolute inset-0 bg-white opacity-30';
1287
+ effect.style.animation = 'fadeOut 0.5s forwards';
1288
+ carViewer.appendChild(effect);
1289
+
1290
+ setTimeout(() => {
1291
+ effect.remove();
1292
+ }, 500);
1293
+ }
1294
+
1295
+ // Play sound effect
1296
+ function playSoundEffect(type) {
1297
+ // In a real app, this would play actual sounds
1298
+ console.log(`Playing ${type} sound effect`);
1299
+ }
1300
+
1301
+ // Create confetti effect
1302
+ function createConfetti() {
1303
+ for (let i = 0; i < 50; i++) {
1304
+ const confetti = document.createElement('div');
1305
+ confetti.className = 'confetti';
1306
+ confetti.style.left = `${Math.random() * 100}%`;
1307
+ confetti.style.animationDelay = `${Math.random() * 2}s`;
1308
+ confetti.style.backgroundColor = `hsl(${Math.random() * 360}, 100%, 50%)`;
1309
+ document.body.appendChild(confetti);
1310
+
1311
+ setTimeout(() => {
1312
+ confetti.remove();
1313
+ }, 3000);
1314
+ }
1315
+ }
1316
+
1317
+ // Global function to remove sticker by ID
1318
+ window.removeStickerById = function(id) {
1319
+ const sticker = state.selectedStickers.find(s => s.id === id);
1320
+ if (sticker) {
1321
+ removeSticker(sticker);
1322
+ }
1323
+ };
1324
+
1325
+ // Initialize the app
1326
+ init();
1327
+ });
1328
+ </script>
1329
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=LukasBe/custom-rides-eshop" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1330
+ </html>