FGF897 commited on
Commit
9a0df66
·
verified ·
1 Parent(s): 30a8a98

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +370 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Ghibligram
3
- emoji: 🐠
4
- colorFrom: blue
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: ghibligram
3
+ emoji: 🐳
4
+ colorFrom: red
5
  colorTo: pink
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,370 @@
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>Retro Ghibli Photobooth</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ @import url('https://fonts.googleapis.com/css2?family=Fredoka+One&family=Patrick+Hand&display=swap');
12
+
13
+ body {
14
+ background-color: #f5e9dc;
15
+ font-family: 'Patrick Hand', cursive;
16
+ overflow-x: hidden;
17
+ }
18
+
19
+ .ghibli-effect {
20
+ filter: sepia(0.3) brightness(1.1) contrast(0.9) saturate(1.2);
21
+ position: relative;
22
+ }
23
+
24
+ .ghibli-effect::after {
25
+ content: '';
26
+ position: absolute;
27
+ top: 0;
28
+ left: 0;
29
+ right: 0;
30
+ bottom: 0;
31
+ background: linear-gradient(to bottom, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0) 50%);
32
+ mix-blend-mode: overlay;
33
+ }
34
+
35
+ .polaroid-frame {
36
+ background: white;
37
+ padding: 15px 15px 60px 15px;
38
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2), 0 10px 20px rgba(0,0,0,0.15);
39
+ transform: rotate(-2deg);
40
+ transition: all 0.3s ease;
41
+ }
42
+
43
+ .polaroid-frame:hover {
44
+ transform: rotate(1deg) scale(1.02);
45
+ }
46
+
47
+ .polaroid-label {
48
+ font-family: 'Fredoka One', cursive;
49
+ color: #333;
50
+ text-align: center;
51
+ margin-top: 10px;
52
+ font-size: 1.2rem;
53
+ }
54
+
55
+ .flash {
56
+ position: fixed;
57
+ top: 0;
58
+ left: 0;
59
+ width: 100%;
60
+ height: 100%;
61
+ background-color: white;
62
+ opacity: 0;
63
+ z-index: 1000;
64
+ pointer-events: none;
65
+ }
66
+
67
+ .camera-shutter {
68
+ animation: shutter 0.8s cubic-bezier(0.4, 0.0, 0.2, 1);
69
+ }
70
+
71
+ @keyframes shutter {
72
+ 0% { transform: scale(1); }
73
+ 50% { transform: scale(0.9); }
74
+ 100% { transform: scale(1); }
75
+ }
76
+
77
+ .photo-strip {
78
+ background: repeating-linear-gradient(
79
+ to bottom,
80
+ #f5e9dc,
81
+ #f5e9dc 20px,
82
+ #d8c9b8 20px,
83
+ #d8c9b8 22px
84
+ );
85
+ box-shadow: inset 0 0 10px rgba(0,0,0,0.2);
86
+ }
87
+
88
+ .vintage-button {
89
+ background: linear-gradient(to bottom, #e74c3c, #c0392b);
90
+ color: white;
91
+ text-shadow: 0 1px 1px rgba(0,0,0,0.3);
92
+ box-shadow: 0 4px 0 #922b21, 0 5px 10px rgba(0,0,0,0.2);
93
+ border-radius: 50px;
94
+ transition: all 0.2s ease;
95
+ }
96
+
97
+ .vintage-button:active {
98
+ transform: translateY(4px);
99
+ box-shadow: 0 1px 0 #922b21, 0 2px 5px rgba(0,0,0,0.2);
100
+ }
101
+
102
+ .film-border {
103
+ border: 8px solid #1a1a1a;
104
+ border-image: repeating-linear-gradient(
105
+ to bottom,
106
+ #1a1a1a,
107
+ #1a1a1a 10px,
108
+ #333 10px,
109
+ #333 20px
110
+ ) 10;
111
+ }
112
+ </style>
113
+ </head>
114
+ <body class="min-h-screen py-8">
115
+ <div class="flash" id="flash"></div>
116
+
117
+ <div class="container mx-auto px-4">
118
+ <h1 class="text-5xl font-bold text-center mb-2 text-amber-900 font-fredoka">Ghibli Photobooth</h1>
119
+ <p class="text-xl text-center mb-8 text-amber-800">Capture magical moments with Studio Ghibli style</p>
120
+
121
+ <div class="flex flex-col lg:flex-row gap-8 items-center justify-center">
122
+ <!-- Camera Section -->
123
+ <div class="w-full lg:w-1/2">
124
+ <div class="bg-black p-4 rounded-lg shadow-2xl film-border">
125
+ <div class="relative overflow-hidden rounded-md" id="cameraView">
126
+ <video id="video" class="w-full h-auto" autoplay playsinline></video>
127
+ <canvas id="canvas" class="hidden"></canvas>
128
+
129
+ <div class="absolute bottom-0 left-0 right-0 bg-black bg-opacity-50 text-white p-4 flex justify-center">
130
+ <button id="captureBtn" class="vintage-button px-8 py-4 text-xl flex items-center gap-2">
131
+ <i class="fas fa-camera-retro"></i> Take Photo
132
+ </button>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <div class="mt-4 flex gap-4 justify-center">
138
+ <button id="ghibliEffectBtn" class="vintage-button px-6 py-3 flex items-center gap-2">
139
+ <i class="fas fa-magic"></i> Ghibli Effect
140
+ </button>
141
+ <button id="downloadBtn" class="vintage-button px-6 py-3 flex items-center gap-2" disabled>
142
+ <i class="fas fa-download"></i> Download
143
+ </button>
144
+ </div>
145
+ </div>
146
+
147
+ <!-- Gallery Section -->
148
+ <div class="w-full lg:w-1/2">
149
+ <div class="bg-white bg-opacity-70 rounded-xl p-6 shadow-lg">
150
+ <h2 class="text-3xl font-bold mb-4 text-amber-900 font-fredoka">Your Photos</h2>
151
+
152
+ <div id="photoStrip" class="photo-strip p-4 rounded-lg min-h-64 flex flex-col items-center gap-6">
153
+ <p class="text-gray-600 italic" id="emptyMessage">Your photos will appear here...</p>
154
+
155
+ <!-- Photos will be added here dynamically -->
156
+ </div>
157
+
158
+ <div class="mt-4 flex justify-between items-center">
159
+ <div class="flex gap-2">
160
+ <button id="clearBtn" class="bg-gray-200 hover:bg-gray-300 px-4 py-2 rounded-lg flex items-center gap-2">
161
+ <i class="fas fa-trash"></i> Clear All
162
+ </button>
163
+ </div>
164
+
165
+ <div class="text-sm text-gray-600">
166
+ <span id="photoCount">0</span> photos
167
+ </div>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
172
+ </div>
173
+
174
+ <script>
175
+ document.addEventListener('DOMContentLoaded', function() {
176
+ // Elements
177
+ const video = document.getElementById('video');
178
+ const canvas = document.getElementById('canvas');
179
+ const captureBtn = document.getElementById('captureBtn');
180
+ const ghibliEffectBtn = document.getElementById('ghibliEffectBtn');
181
+ const downloadBtn = document.getElementById('downloadBtn');
182
+ const clearBtn = document.getElementById('clearBtn');
183
+ const photoStrip = document.getElementById('photoStrip');
184
+ const emptyMessage = document.getElementById('emptyMessage');
185
+ const photoCount = document.getElementById('photoCount');
186
+ const flash = document.getElementById('flash');
187
+
188
+ // State
189
+ let currentPhoto = null;
190
+ let photos = [];
191
+ let ghibliEffectEnabled = true;
192
+
193
+ // Initialize camera
194
+ async function initCamera() {
195
+ try {
196
+ const stream = await navigator.mediaDevices.getUserMedia({
197
+ video: {
198
+ width: { ideal: 1280 },
199
+ height: { ideal: 720 },
200
+ facingMode: 'user'
201
+ },
202
+ audio: false
203
+ });
204
+ video.srcObject = stream;
205
+ } catch (err) {
206
+ console.error("Error accessing camera:", err);
207
+ alert("Could not access the camera. Please make sure you've granted camera permissions.");
208
+ }
209
+ }
210
+
211
+ // Capture photo
212
+ captureBtn.addEventListener('click', function() {
213
+ // Flash effect
214
+ flash.style.opacity = 1;
215
+ setTimeout(() => { flash.style.opacity = 0; }, 200);
216
+
217
+ // Camera shutter animation
218
+ const cameraView = document.getElementById('cameraView');
219
+ cameraView.classList.add('camera-shutter');
220
+ setTimeout(() => cameraView.classList.remove('camera-shutter'), 800);
221
+
222
+ // Capture the image
223
+ const context = canvas.getContext('2d');
224
+ canvas.width = video.videoWidth;
225
+ canvas.height = video.videoHeight;
226
+ context.drawImage(video, 0, 0, canvas.width, canvas.height);
227
+
228
+ // Create photo object
229
+ currentPhoto = {
230
+ id: Date.now(),
231
+ imageData: canvas.toDataURL('image/png'),
232
+ hasGhibliEffect: ghibliEffectEnabled
233
+ };
234
+
235
+ // Add to gallery
236
+ addPhotoToGallery(currentPhoto);
237
+ downloadBtn.disabled = false;
238
+
239
+ // Play shutter sound
240
+ playShutterSound();
241
+ });
242
+
243
+ // Toggle Ghibli effect
244
+ ghibliEffectBtn.addEventListener('click', function() {
245
+ ghibliEffectEnabled = !ghibliEffectEnabled;
246
+ ghibliEffectBtn.innerHTML = ghibliEffectEnabled ?
247
+ '<i class="fas fa-magic"></i> Ghibli Effect (ON)' :
248
+ '<i class="fas fa-magic"></i> Ghibli Effect (OFF)';
249
+
250
+ ghibliEffectBtn.classList.toggle('bg-green-600', ghibliEffectEnabled);
251
+ ghibliEffectBtn.classList.toggle('bg-gray-600', !ghibliEffectEnabled);
252
+ });
253
+
254
+ // Download current photo
255
+ downloadBtn.addEventListener('click', function() {
256
+ if (!currentPhoto) return;
257
+
258
+ const link = document.createElement('a');
259
+ link.download = `ghibli-photo-${new Date().toISOString().slice(0,10)}.png`;
260
+ link.href = currentPhoto.imageData;
261
+ link.click();
262
+ });
263
+
264
+ // Clear all photos
265
+ clearBtn.addEventListener('click', function() {
266
+ if (confirm('Are you sure you want to delete all photos?')) {
267
+ photoStrip.innerHTML = '<p class="text-gray-600 italic" id="emptyMessage">Your photos will appear here...</p>';
268
+ photos = [];
269
+ currentPhoto = null;
270
+ updatePhotoCount();
271
+ downloadBtn.disabled = true;
272
+ emptyMessage.style.display = 'block';
273
+ }
274
+ });
275
+
276
+ // Add photo to gallery
277
+ function addPhotoToGallery(photo) {
278
+ emptyMessage.style.display = 'none';
279
+
280
+ const photoElement = document.createElement('div');
281
+ photoElement.className = 'polaroid-frame w-64';
282
+ photoElement.dataset.id = photo.id;
283
+
284
+ const img = document.createElement('img');
285
+ img.src = photo.imageData;
286
+ img.className = 'w-full h-auto';
287
+ if (photo.hasGhibliEffect) {
288
+ img.classList.add('ghibli-effect');
289
+ }
290
+
291
+ const label = document.createElement('div');
292
+ label.className = 'polaroid-label';
293
+ label.textContent = `Ghibli #${photos.length + 1}`;
294
+
295
+ photoElement.appendChild(img);
296
+ photoElement.appendChild(label);
297
+
298
+ // Add delete button to each photo
299
+ const deleteBtn = document.createElement('button');
300
+ deleteBtn.className = 'absolute top-2 right-2 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity';
301
+ deleteBtn.innerHTML = '<i class="fas fa-times text-xs"></i>';
302
+ deleteBtn.addEventListener('click', function(e) {
303
+ e.stopPropagation();
304
+ if (confirm('Delete this photo?')) {
305
+ photoElement.remove();
306
+ photos = photos.filter(p => p.id !== photo.id);
307
+ updatePhotoCount();
308
+
309
+ if (photos.length === 0) {
310
+ emptyMessage.style.display = 'block';
311
+ downloadBtn.disabled = true;
312
+ }
313
+ }
314
+ });
315
+
316
+ photoElement.style.position = 'relative';
317
+ photoElement.appendChild(deleteBtn);
318
+
319
+ // Hover effect to show delete button
320
+ photoElement.addEventListener('mouseenter', () => {
321
+ deleteBtn.classList.remove('opacity-0');
322
+ deleteBtn.classList.add('opacity-70');
323
+ });
324
+
325
+ photoElement.addEventListener('mouseleave', () => {
326
+ deleteBtn.classList.remove('opacity-70');
327
+ deleteBtn.classList.add('opacity-0');
328
+ });
329
+
330
+ // Click to set as current photo
331
+ photoElement.addEventListener('click', function() {
332
+ currentPhoto = photos.find(p => p.id === photo.id);
333
+ downloadBtn.disabled = false;
334
+ });
335
+
336
+ photoStrip.insertBefore(photoElement, photoStrip.firstChild);
337
+ photos.unshift(photo);
338
+ updatePhotoCount();
339
+ }
340
+
341
+ // Update photo counter
342
+ function updatePhotoCount() {
343
+ photoCount.textContent = photos.length;
344
+ }
345
+
346
+ // Play shutter sound
347
+ function playShutterSound() {
348
+ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
349
+ const oscillator = audioContext.createOscillator();
350
+ const gainNode = audioContext.createGain();
351
+
352
+ oscillator.connect(gainNode);
353
+ gainNode.connect(audioContext.destination);
354
+
355
+ oscillator.type = 'sine';
356
+ oscillator.frequency.value = 1000;
357
+ gainNode.gain.value = 0.5;
358
+
359
+ oscillator.start();
360
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
361
+ oscillator.stop(audioContext.currentTime + 0.3);
362
+ }
363
+
364
+ // Initialize
365
+ initCamera();
366
+ ghibliEffectBtn.click(); // Set initial state to ON
367
+ });
368
+ </script>
369
+ <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=FGF897/ghibligram" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
370
+ </html>