]> git.cworth.org Git - zombocom-ai/blob - index.html
Tell server a name at first connection
[zombocom-ai] / index.html
1 <!DOCTYPE html>
2 <html>
3
4 <head>
5   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6   <title>ZOMBO</title>
7   <link href="/zombo.css" rel="stylesheet" type="text/css">
8   <meta name="viewport" content="width=device-width,initial-scale=1">
9   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
10   <meta name="HandheldFriendly" content="true">
11 </head>
12
13 <body>
14   <div id="content">
15
16     <div id="header" align="center">
17       <p>
18         <br>
19       </p>
20
21       <p>
22         <img src="/zombocom.png" alt="Zombocom" longdesc="http://zombo.com" width="1199" height="217">
23       </p>
24     </div>
25
26     <p>
27       Welcome to Zombocom. You can do anything at Zombocom, anything at
28       all. The only limit is yourself!
29     </p>
30
31     <dialog id="name-dialog">
32       <form method="dialog">
33         <p>
34           <label>Your name:
35             <input id="name" type="text" autocomplete="off">
36           </label>
37         </p>
38         <div>
39           <button value="default">OK</button>
40         </div>
41       </form>
42     </dialog>
43
44     <p>
45       <div id="spinner" align="center">
46         <div class="animate-flicker">
47           <p>
48             <img src="/pngwheel.png" class="rotate thefade">
49           </p>
50         </div>
51       </div>
52
53       <form action="" id="zombo-form">
54         <div class="form-row large">
55           <label for="prompt">
56             What can you imagine?
57           </label>
58           <button id="safety" type="button">Safety prompt</button>
59           <textarea id="prompt" rows="4" width="100%" autocomplete="off" required></textarea>
60         </div>
61
62         <div class="form-row small left">
63           <div class="labeled-row">
64             <label for="code">
65               Numeric code:
66             </label>
67             <input id="code" type="number" min="0" max="4294967295" autocomplete="off" placeholder="(Leave blank for random)" />
68           </div>
69         </div>
70
71         <div class="form-row large">
72           <button id="generate" type="submit">Make the infinite possible</button>
73         </div>
74       </form>
75     </p>
76
77     <div id="images">
78     </div>
79
80     <audio loop="" src="/zombo_words.mp3" type="audio/mpeg"></audio>
81     <button id="mute" class="menu-button fade volume">
82       <div>🔊</div>
83       <script>
84 const mute = document.querySelector("#mute");
85 const icon = document.querySelector("#mute > div");
86 const audio = document.querySelector("audio");
87
88 mute.addEventListener("click", () => {
89   if (audio.paused) {
90       audio.volume = 0.2;
91       audio.play();
92       icon.innerHTML = "🔈";
93   } else {
94       audio.pause();
95       icon.innerHTML = "🔊";
96   }
97   mute.classList.add("fade");
98 });
99       </script>
100
101     </button>
102
103     <button id="profile" class="menu-button">
104       <div>👤</div>
105     </button>
106
107   </div>
108
109   <script src="/socket.io/socket.io.js"></script>
110   <script>
111     var socket = io();
112
113     const name_input = document.querySelector("#name");
114     const name_dialog = document.querySelector("#name-dialog");
115     var informed_name;
116     const images = document.querySelector("#images");
117     const zombo_form = document.querySelector("#zombo-form");
118     const prompt = document.querySelector("#prompt");
119     const code = document.querySelector("#code");
120     const safety= document.querySelector("#safety");
121     const spinner = document.querySelector("#spinner");
122     const profile = document.querySelector("#profile");
123     var spinner_timeout;
124
125     profile.addEventListener('click', () => {
126         name_dialog.showModal();
127     });
128
129     name_dialog.addEventListener('close', () => {
130         socket.emit('set-name', name_input.value);
131     });
132
133     socket.on('comment', function(comment) {
134         const comments = document.querySelector("#" + comment.comments_id);
135         const dt = document.createElement('dt');
136         const dd = document.createElement('dd');
137         dt.textContent = comment.name + ':';
138         dd.textContent = comment.text;
139         comments.appendChild(dt);
140         comments.appendChild(dd);
141     });
142
143     socket.on('inform-name', (name) => {
144         console.log("Received inform-name event: " + name);
145
146         /* When we receive a name we store it in 3 places:
147          *
148          *   * The informed_name variable (confirming what the server knows)
149          *   * The name_input field (so the user will see that in their profile)
150          *   * In localStorage (for use in a future session)
151          */
152         informed_name = name;
153         name_input.value = name;
154         localStorage.setItem('name', name);
155     });
156
157     socket.on('reset', () => {
158         images.replaceChildren();
159
160         /* Since the server is seeing us for the first time, let it
161            know our name (if we have one). */
162         const name = localStorage.getItem('name');
163         if (name) {
164             socket.emit('set-name', name);
165             return;
166         }
167     });
168
169     socket.on('image', (image) => {
170         const figure = document.createElement('figure');
171
172         const img = document.createElement('img');
173         img.src = image.filename;
174         figure.appendChild(img);
175
176         const figcaption = document.createElement('figcaption');
177         const caption_text = document.createTextNode(`${image.prompt} (${image.code}) `);
178         figcaption.appendChild(caption_text);
179
180         const reuse_button = document.createElement('button');
181         reuse_button.appendChild(document.createTextNode("Reuse"));
182         figcaption.appendChild(reuse_button);
183
184         reuse_button.addEventListener('click', () => {
185             prompt.value = image.prompt;
186             window.scrollTo(0,0);
187         });
188
189         figure.appendChild(figcaption);
190
191         const dl_comments = document.createElement('dl');
192         const comments_id = "comments_" + image.index;
193         dl_comments.className = "comments";
194         dl_comments.id = comments_id;
195         figure.appendChild(dl_comments);
196
197         const comment_form = document.createElement('form');
198         const comment_input = document.createElement('input')
199         comment_input.type = "text";
200         comment_input.className = "comment";
201         comment_input.placeholder = "Add a comment";
202         comment_form.appendChild(comment_input);
203         figure.appendChild(comment_form);
204
205         comment_input.addEventListener('focus', () => {
206             /* If the server has informed us it has our name, we are done. */
207             if (informed_name)
208                 return;
209
210             /* If server has no name, check local storage. */
211             const name = localStorage.getItem('name');
212             if (name) {
213                 socket.emit('set-name', name);
214                 return;
215             }
216
217             /* Failing both, bring up the modal dialog to set the name. */
218             name_dialog.showModal();
219         });
220
221         comment_form.addEventListener('submit', function(e) {
222             e.preventDefault();
223             if (comment_input.value) {
224                 socket.emit('comment', {comments_id: comments_id,
225                                         text: comment_input.value});
226                 comment_input.value = '';
227             }
228         });
229
230         images.prepend(figure);
231     });
232
233     function hide_spinner() {
234         zombo_form.style.display = "grid";
235         spinner.style.display = "none";
236     }
237
238     zombo_form.addEventListener('submit', function(e) {
239         e.preventDefault();
240         /* Hide the form and show spinner while generation is happening. */
241         zombo_form.style.display = "none";
242         spinner.style.display = "block";
243         spinner_timeout = setTimeout(hide_spinner, 60000);
244         socket.emit('generate', {"prompt": prompt.value, "code": code.value});
245         prompt.value = '';
246     });
247
248     socket.on('generation-done', () => {
249         /* Re-display the form and hide spinner now that generation is over. */
250         clearTimeout(spinner_timeout);
251         hide_spinner();
252     });
253
254     function random_from(items) {
255         return items[Math.floor(Math.random()*items.length)];
256     }
257
258     safety.addEventListener("click", () => {
259         const art_type = [
260             "A portrait of",
261             "A hyperrealistic photograph of",
262             "A matte painting of",
263             "Epic fantasy card art of",
264             "Professional oil painting of",
265             "An image of",
266             "A pencil sketch of",
267             "A watercolor of",
268             "A 3D rendering of",
269             "A marble statue of",
270         ];
271         const subject = [
272             " a modern home",
273             " crashing waves",
274             " a Porsche 911 Carrera",
275             " a Halo spartan",
276             " a cute cat",
277             " a mad scientist",
278             " an elfin princess",
279             " sci-fi buildings",
280             " pastel purple clouds",
281             " a Teenage Mutant Ninja Turtle",
282             " Pikachu",
283         ];
284         const scenery = [
285             " in tropical surroundings",
286             " in space",
287             " in an ocean storm",
288             " in a snowy forest",
289             " in a cardboard box",
290             " holding an axe",
291             " in an epic landscape",
292             " in a haunted forest",
293             " riding a motorbike",
294             " in a futuristic city at night",
295             " in a dystopian landscape, foggy",
296             " in the land of snow",
297             " that looks like a watermelon",
298             " on the streets of London at night with neon lights flashing",
299             " that is part octopus",
300             " melting into a puddle",
301             " on a birthday cake",
302         ];
303         const artist = [
304             ", unreal engine 5",
305             ", concept art",
306             ", graphic novel",
307             " by Vincent Van Gogh",
308             " by Claude Monet",
309             " by Johannes Vermeer",
310             ", fantasy art, neon fog",
311             ", epic lighting from above",
312             ", trending on artstation",
313             " by Gustav Klimt",
314             " by Leonardo da Vinci",
315         ];
316
317         prompt.value = random_from(art_type) + random_from(subject) +
318             random_from(scenery) + random_from(artist);
319         return false;
320     });
321
322   </script>
323 </body>
324 </html>