Spaces:
Running
on
Zero
Running
on
Zero
Update dna-slot-machine.html
Browse files- dna-slot-machine.html +597 -307
dna-slot-machine.html
CHANGED
@@ -3,8 +3,10 @@
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
-
<title
|
7 |
<style>
|
|
|
|
|
8 |
* {
|
9 |
margin: 0;
|
10 |
padding: 0;
|
@@ -12,9 +14,9 @@
|
|
12 |
}
|
13 |
|
14 |
body {
|
15 |
-
background: #
|
16 |
color: #fff;
|
17 |
-
font-family: '
|
18 |
overflow-x: hidden;
|
19 |
display: flex;
|
20 |
flex-direction: column;
|
@@ -25,7 +27,32 @@
|
|
25 |
padding-top: 10px;
|
26 |
}
|
27 |
|
|
|
28 |
body::before {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
content: '';
|
30 |
position: fixed;
|
31 |
top: 0;
|
@@ -46,164 +73,253 @@
|
|
46 |
rgba(0,0,0,0.05) 1px,
|
47 |
transparent 1px,
|
48 |
transparent 2px
|
49 |
-
),
|
50 |
-
repeating-linear-gradient(
|
51 |
-
45deg,
|
52 |
-
transparent 0px,
|
53 |
-
rgba(255,255,255,0.03) 1px,
|
54 |
-
transparent 2px,
|
55 |
-
transparent 3px
|
56 |
-
),
|
57 |
-
repeating-linear-gradient(
|
58 |
-
-45deg,
|
59 |
-
transparent 0px,
|
60 |
-
rgba(0,0,0,0.03) 1px,
|
61 |
-
transparent 2px,
|
62 |
-
transparent 3px
|
63 |
);
|
64 |
-
background-size: 2px 2px, 2px 2px
|
65 |
pointer-events: none;
|
66 |
z-index: 1;
|
67 |
opacity: 0.8;
|
68 |
animation: staticNoise 0.1s steps(8) infinite;
|
69 |
}
|
70 |
|
71 |
-
body::after {
|
72 |
-
content: '';
|
73 |
-
position: fixed;
|
74 |
-
top: 0;
|
75 |
-
left: 0;
|
76 |
-
width: 100%;
|
77 |
-
height: 100%;
|
78 |
-
background:
|
79 |
-
radial-gradient(circle at 17% 23%, rgba(255,255,255,0.1) 0px, transparent 1px),
|
80 |
-
radial-gradient(circle at 67% 71%, rgba(0,0,0,0.08) 0px, transparent 1px),
|
81 |
-
radial-gradient(circle at 41% 57%, rgba(255,255,255,0.06) 0px, transparent 1px),
|
82 |
-
radial-gradient(circle at 89% 13%, rgba(0,0,0,0.07) 0px, transparent 1px),
|
83 |
-
radial-gradient(circle at 23% 89%, rgba(255,255,255,0.05) 0px, transparent 1px);
|
84 |
-
background-size: 3px 3px, 2px 2px, 4px 4px, 2px 2px, 3px 3px;
|
85 |
-
pointer-events: none;
|
86 |
-
z-index: 1;
|
87 |
-
animation: staticNoise 0.15s steps(10) infinite reverse;
|
88 |
-
}
|
89 |
-
|
90 |
@keyframes staticNoise {
|
91 |
0%, 100% { transform: translate(0, 0); }
|
92 |
-
|
93 |
-
20% { transform: translate(1px, 0px); }
|
94 |
-
30% { transform: translate(0px, 1px); }
|
95 |
-
40% { transform: translate(-1px, 1px); }
|
96 |
-
50% { transform: translate(1px, -1px); }
|
97 |
-
60% { transform: translate(-1px, 0px); }
|
98 |
-
70% { transform: translate(0px, -1px); }
|
99 |
-
80% { transform: translate(1px, 1px); }
|
100 |
-
90% { transform: translate(-1px, -1px); }
|
101 |
}
|
102 |
|
|
|
103 |
.machine-container {
|
104 |
-
background: linear-gradient(145deg, #
|
105 |
-
border
|
106 |
-
|
107 |
-
padding
|
108 |
-
|
109 |
-
|
|
|
|
|
|
|
110 |
width: 95vw;
|
111 |
max-width: 1400px;
|
112 |
position: relative;
|
113 |
z-index: 2;
|
114 |
}
|
115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
.title {
|
117 |
text-align: center;
|
118 |
-
font-
|
119 |
-
|
120 |
-
|
121 |
-
|
|
|
|
|
122 |
}
|
123 |
|
124 |
.title a {
|
125 |
text-decoration: none;
|
126 |
-
|
127 |
-
-
|
128 |
-
|
129 |
-
|
130 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
}
|
132 |
|
133 |
-
|
134 |
-
|
|
|
|
|
135 |
}
|
136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
.cell-type-selector {
|
138 |
display: flex;
|
139 |
align-items: center;
|
140 |
justify-content: center;
|
141 |
gap: 20px;
|
142 |
-
margin-bottom:
|
143 |
-
}
|
144 |
-
|
145 |
-
.cell-type-label {
|
146 |
-
font-size: 1.2rem;
|
147 |
-
color: #ccc;
|
148 |
}
|
149 |
|
150 |
.radio-group {
|
151 |
display: flex;
|
152 |
-
gap:
|
153 |
}
|
154 |
|
155 |
-
.
|
|
|
156 |
display: flex;
|
157 |
align-items: center;
|
158 |
-
|
|
|
|
|
159 |
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
font-size: 1.1rem;
|
161 |
color: #fff;
|
162 |
-
|
|
|
|
|
163 |
}
|
164 |
|
165 |
-
|
166 |
-
|
|
|
167 |
}
|
168 |
|
169 |
-
.
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
}
|
175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
.reels-container {
|
177 |
background: #000;
|
178 |
-
border:
|
179 |
-
border-radius:
|
180 |
-
padding:
|
181 |
max-width: 100%;
|
182 |
position: relative;
|
183 |
-
box-shadow:
|
|
|
|
|
184 |
overflow: visible;
|
|
|
185 |
}
|
186 |
|
187 |
.reels-wrapper {
|
188 |
display: flex;
|
189 |
-
gap:
|
190 |
min-width: fit-content;
|
191 |
-
padding:
|
192 |
justify-content: center;
|
193 |
flex-wrap: wrap;
|
194 |
max-width: 1200px;
|
195 |
margin: 0 auto;
|
|
|
|
|
|
|
|
|
196 |
}
|
197 |
|
198 |
.reel {
|
199 |
-
width:
|
200 |
-
height:
|
201 |
background: #ffffff;
|
202 |
-
border:
|
203 |
-
border-radius:
|
204 |
overflow: hidden;
|
205 |
position: relative;
|
206 |
-
box-shadow:
|
|
|
|
|
207 |
}
|
208 |
|
209 |
.reel-strip {
|
@@ -213,305 +329,385 @@
|
|
213 |
}
|
214 |
|
215 |
.nucleotide {
|
216 |
-
height:
|
217 |
display: flex;
|
218 |
align-items: center;
|
219 |
justify-content: center;
|
220 |
-
font-size:
|
221 |
font-weight: bold;
|
222 |
background: #ffffff;
|
|
|
223 |
}
|
224 |
|
225 |
-
.nucleotide.A { color: #00ff00; }
|
226 |
-
.nucleotide.T { color: #ff0000; }
|
227 |
-
.nucleotide.C { color: #
|
228 |
-
.nucleotide.G { color: #
|
229 |
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
|
|
|
|
|
|
236 |
}
|
237 |
|
238 |
-
.
|
239 |
-
|
240 |
-
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
font-size: 1.5rem;
|
243 |
font-weight: bold;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
border-radius: 50px;
|
245 |
cursor: pointer;
|
246 |
text-transform: uppercase;
|
247 |
-
letter-spacing:
|
248 |
-
box-shadow:
|
|
|
|
|
|
|
249 |
transition: all 0.3s ease;
|
250 |
color: #fff;
|
251 |
-
text-shadow: 0
|
252 |
position: relative;
|
253 |
overflow: hidden;
|
|
|
254 |
}
|
255 |
|
256 |
.spin-button::before {
|
257 |
content: '';
|
258 |
position: absolute;
|
259 |
-
top:
|
260 |
-
left:
|
261 |
-
width:
|
262 |
-
height:
|
263 |
-
background
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
radial-gradient(circle at 70% 20%, #00ff00 0px, transparent 2px),
|
269 |
-
radial-gradient(circle at 10% 60%, #ff0000 0px, transparent 2px),
|
270 |
-
radial-gradient(circle at 90% 40%, #0000ff 0px, transparent 2px),
|
271 |
-
radial-gradient(circle at 40% 10%, #ffa500 0px, transparent 2px);
|
272 |
-
background-size: 20px 20px, 25px 25px, 30px 30px, 15px 15px,
|
273 |
-
18px 18px, 22px 22px, 28px 28px, 24px 24px;
|
274 |
-
opacity: 0.25;
|
275 |
-
animation: nucleotideNoise 0.8s steps(6) infinite;
|
276 |
-
}
|
277 |
-
|
278 |
-
.spin-button::after {
|
279 |
-
content: '';
|
280 |
-
position: absolute;
|
281 |
-
top: 0;
|
282 |
-
left: 0;
|
283 |
-
width: 100%;
|
284 |
-
height: 100%;
|
285 |
-
background-image:
|
286 |
-
radial-gradient(circle at 60% 40%, #00ff00 0px, transparent 1px),
|
287 |
-
radial-gradient(circle at 25% 75%, #ff0000 0px, transparent 1px),
|
288 |
-
radial-gradient(circle at 85% 15%, #0000ff 0px, transparent 1px),
|
289 |
-
radial-gradient(circle at 15% 25%, #ffa500 0px, transparent 1px);
|
290 |
-
background-size: 10px 10px, 12px 12px, 14px 14px, 16px 16px;
|
291 |
-
opacity: 0.2;
|
292 |
-
animation: nucleotideNoise 1.2s steps(8) infinite reverse;
|
293 |
-
}
|
294 |
-
|
295 |
-
@keyframes nucleotideNoise {
|
296 |
-
0% { transform: translate(0, 0) scale(1); }
|
297 |
-
16% { transform: translate(-2px, 1px) scale(1.02); }
|
298 |
-
33% { transform: translate(1px, -2px) scale(0.98); }
|
299 |
-
50% { transform: translate(-1px, 2px) scale(1.01); }
|
300 |
-
66% { transform: translate(2px, -1px) scale(0.99); }
|
301 |
-
83% { transform: translate(-2px, -2px) scale(1.02); }
|
302 |
-
100% { transform: translate(1px, 1px) scale(1); }
|
303 |
-
}
|
304 |
-
|
305 |
-
.spin-button span {
|
306 |
-
position: relative;
|
307 |
-
z-index: 2;
|
308 |
}
|
309 |
|
310 |
-
|
311 |
-
transform:
|
312 |
-
|
313 |
-
background: #5a5a5a;
|
314 |
}
|
315 |
|
316 |
-
.spin-button:hover
|
317 |
-
|
318 |
-
|
|
|
|
|
319 |
}
|
320 |
|
321 |
.spin-button:active {
|
322 |
-
transform: translateY(0);
|
323 |
}
|
324 |
|
325 |
.spin-button:disabled {
|
326 |
-
background: #444;
|
327 |
cursor: not-allowed;
|
328 |
box-shadow: none;
|
|
|
329 |
}
|
330 |
|
|
|
331 |
.sequence-display {
|
332 |
-
background: #
|
333 |
-
border:
|
334 |
-
border-radius:
|
335 |
-
padding:
|
336 |
-
font-family: '
|
337 |
font-size: 0.9rem;
|
338 |
-
letter-spacing:
|
339 |
width: 100%;
|
340 |
max-width: 1200px;
|
341 |
-
|
342 |
-
|
343 |
-
|
|
|
344 |
position: relative;
|
345 |
-
|
346 |
}
|
347 |
|
348 |
.sequence-display::before {
|
349 |
-
content: 'SYNTHETIC REGULATORY ELEMENT';
|
350 |
position: absolute;
|
351 |
-
top: -
|
352 |
left: 50%;
|
353 |
transform: translateX(-50%);
|
354 |
-
background: #
|
355 |
-
padding: 0
|
356 |
-
font-size: 0.
|
357 |
-
color: #
|
358 |
-
letter-spacing:
|
359 |
-
|
360 |
}
|
361 |
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
367 |
}
|
368 |
|
369 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
text-align: center;
|
371 |
-
|
372 |
-
|
|
|
373 |
}
|
374 |
|
375 |
-
.
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
|
|
|
|
|
|
384 |
}
|
385 |
|
386 |
-
.
|
|
|
|
|
|
|
|
|
387 |
color: #fff;
|
388 |
-
|
389 |
-
|
390 |
-
text-shadow: 0 0 5px rgba(0,255,136,0.5);
|
391 |
}
|
392 |
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
}
|
398 |
|
399 |
-
.
|
400 |
-
|
|
|
|
|
|
|
401 |
}
|
402 |
|
403 |
-
.
|
404 |
-
|
|
|
|
|
|
|
|
|
405 |
}
|
406 |
|
407 |
-
|
408 |
-
|
409 |
-
|
|
|
|
|
410 |
}
|
411 |
|
412 |
-
.
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
z-index: 3;
|
418 |
-
width: 60px;
|
419 |
-
height: 200px;
|
420 |
}
|
421 |
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
|
|
|
|
|
|
|
|
427 |
}
|
428 |
|
429 |
-
.
|
430 |
-
|
431 |
-
top:
|
432 |
-
|
433 |
-
width: 40px;
|
434 |
-
height: 60px;
|
435 |
-
background: linear-gradient(180deg, #555, #333);
|
436 |
-
border-radius: 5px 0 0 5px;
|
437 |
-
box-shadow:
|
438 |
-
0 3px 10px rgba(0,0,0,0.3),
|
439 |
-
inset 0 1px 2px rgba(255,255,255,0.1);
|
440 |
}
|
441 |
|
442 |
-
.
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
|
|
452 |
}
|
453 |
|
454 |
-
.
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
height: 80px;
|
460 |
-
background: linear-gradient(180deg, #d0d0d0, #a0a0a0);
|
461 |
-
border-radius: 5px;
|
462 |
-
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
463 |
-
transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
464 |
}
|
465 |
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
left: 50%;
|
470 |
-
transform: translateX(-50%);
|
471 |
-
width: 60px;
|
472 |
-
height: 60px;
|
473 |
-
background: radial-gradient(circle at 35% 35%, #ff8888, #ff4444, #cc0000);
|
474 |
-
border-radius: 50%;
|
475 |
-
box-shadow:
|
476 |
-
0 5px 15px rgba(0,0,0,0.4),
|
477 |
-
inset -5px -5px 10px rgba(0,0,0,0.3),
|
478 |
-
inset 3px 3px 5px rgba(255,255,255,0.5);
|
479 |
}
|
480 |
|
481 |
-
|
482 |
-
|
483 |
-
|
|
|
484 |
}
|
485 |
|
486 |
-
/*
|
487 |
@keyframes continuousSpin {
|
488 |
from { transform: translateY(0); }
|
489 |
-
to { transform: translateY(-
|
490 |
}
|
491 |
|
492 |
.reel-strip.loading {
|
493 |
animation: continuousSpin 1s linear infinite;
|
494 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
495 |
</style>
|
496 |
</head>
|
497 |
<body>
|
498 |
<div class="machine-container">
|
499 |
-
<h1 class="title"><a href="https://github.com/pinellolab/DNA-Diffusion" target="_blank" rel="noopener noreferrer"
|
|
|
|
|
|
|
|
|
|
|
|
|
500 |
|
501 |
<div class="cell-type-selector">
|
502 |
-
<label class="cell-type-label">Cell Type-Specific Generation:</label>
|
503 |
<div class="radio-group">
|
504 |
-
<label class="
|
505 |
<input type="radio" name="cellType" value="K562" checked>
|
506 |
-
<
|
507 |
</label>
|
508 |
-
<label class="
|
509 |
<input type="radio" name="cellType" value="GM12878">
|
510 |
-
<
|
511 |
</label>
|
512 |
-
<label class="
|
513 |
<input type="radio" name="cellType" value="HepG2">
|
514 |
-
<
|
515 |
</label>
|
516 |
</div>
|
517 |
</div>
|
@@ -520,9 +716,7 @@
|
|
520 |
<div class="reels-wrapper" id="reelsWrapper"></div>
|
521 |
<div class="lever-container">
|
522 |
<div class="lever" id="lever">
|
523 |
-
<div class="lever-mount">
|
524 |
-
<div class="lever-pivot"></div>
|
525 |
-
</div>
|
526 |
<div class="lever-arm">
|
527 |
<div class="lever-ball"></div>
|
528 |
</div>
|
@@ -531,19 +725,32 @@
|
|
531 |
</div>
|
532 |
|
533 |
<div class="controls">
|
534 |
-
<button class="spin-button" id="spinButton"><span
|
|
|
535 |
<div class="sequence-display" id="sequenceDisplay">
|
536 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
537 |
</div>
|
538 |
</div>
|
539 |
|
540 |
<div class="info">
|
541 |
-
|
542 |
</div>
|
543 |
|
544 |
<div class="lab-credit">
|
545 |
<a href="https://pinellolab.org" target="_blank" rel="noopener noreferrer">
|
546 |
-
|
547 |
</a>
|
548 |
</div>
|
549 |
</div>
|
@@ -597,12 +804,18 @@
|
|
597 |
|
598 |
// Set initial position to show a random nucleotide
|
599 |
const randomIndex = Math.floor(Math.random() * 4);
|
600 |
-
const initialOffset = -randomIndex *
|
601 |
reel.strip.style.transform = `translateY(${initialOffset}px)`;
|
602 |
-
reel.currentPosition = randomIndex *
|
603 |
}
|
604 |
}
|
605 |
|
|
|
|
|
|
|
|
|
|
|
|
|
606 |
function startContinuousSpinning() {
|
607 |
reels.forEach((reel, index) => {
|
608 |
// Add continuous spinning animation
|
@@ -613,10 +826,64 @@
|
|
613 |
const delay = (index % 10) * 0.1;
|
614 |
reel.strip.style.animationDelay = `${delay}s`;
|
615 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
616 |
}
|
617 |
|
618 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
619 |
TARGET_SEQUENCE = sequence;
|
|
|
620 |
|
621 |
reels.forEach((reel, index) => {
|
622 |
// Remove continuous spinning
|
@@ -625,7 +892,7 @@
|
|
625 |
// Calculate target position
|
626 |
const targetNucleotide = TARGET_SEQUENCE[index];
|
627 |
const targetIndex = NUCLEOTIDES.indexOf(targetNucleotide);
|
628 |
-
const finalPosition = targetIndex *
|
629 |
|
630 |
// Set up the final positioning animation
|
631 |
setTimeout(() => {
|
@@ -643,9 +910,15 @@
|
|
643 |
const lever = document.getElementById('lever');
|
644 |
|
645 |
container.classList.remove('spinning');
|
646 |
-
container.classList.add('
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
647 |
|
648 |
-
display.innerHTML = `<strong>Generated Sequence:</strong><br>${TARGET_SEQUENCE}`;
|
649 |
button.disabled = false;
|
650 |
isSpinning = false;
|
651 |
|
@@ -653,8 +926,8 @@
|
|
653 |
lever.classList.remove('pulled');
|
654 |
|
655 |
setTimeout(() => {
|
656 |
-
container.classList.remove('
|
657 |
-
},
|
658 |
}, 1500);
|
659 |
}
|
660 |
|
@@ -666,12 +939,16 @@
|
|
666 |
const display = document.getElementById('sequenceDisplay');
|
667 |
const container = document.getElementById('reelsContainer');
|
668 |
const lever = document.getElementById('lever');
|
|
|
|
|
|
|
|
|
669 |
|
670 |
// Pull the lever
|
671 |
lever.classList.add('pulled');
|
672 |
|
673 |
button.disabled = true;
|
674 |
-
display.
|
675 |
container.classList.add('spinning');
|
676 |
|
677 |
// Start continuous spinning immediately
|
@@ -703,8 +980,8 @@
|
|
703 |
// Listen for messages from parent window
|
704 |
window.addEventListener('message', (event) => {
|
705 |
if (event.data.type === 'sequence_generated') {
|
706 |
-
// Stop spinning and show the actual sequence
|
707 |
-
stopAndShowSequence(event.data.sequence);
|
708 |
} else if (event.data.type === 'generation_error') {
|
709 |
// Stop spinning and show error
|
710 |
reels.forEach(reel => {
|
@@ -717,10 +994,11 @@
|
|
717 |
const lever = document.getElementById('lever');
|
718 |
|
719 |
container.classList.remove('spinning');
|
720 |
-
display.innerHTML = '<strong style="color: #
|
721 |
button.disabled = false;
|
722 |
isSpinning = false;
|
723 |
lever.classList.remove('pulled');
|
|
|
724 |
}
|
725 |
});
|
726 |
|
@@ -731,6 +1009,18 @@
|
|
731 |
startGeneration();
|
732 |
}
|
733 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
734 |
</script>
|
735 |
</body>
|
736 |
</html>
|
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>𧬠DNA CASINO - Protein Synthesis Slot Machine</title>
|
7 |
<style>
|
8 |
+
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Bebas+Neue&display=swap');
|
9 |
+
|
10 |
* {
|
11 |
margin: 0;
|
12 |
padding: 0;
|
|
|
14 |
}
|
15 |
|
16 |
body {
|
17 |
+
background: #000;
|
18 |
color: #fff;
|
19 |
+
font-family: 'Orbitron', monospace;
|
20 |
overflow-x: hidden;
|
21 |
display: flex;
|
22 |
flex-direction: column;
|
|
|
27 |
padding-top: 10px;
|
28 |
}
|
29 |
|
30 |
+
/* Casino carpet pattern background */
|
31 |
body::before {
|
32 |
+
content: '';
|
33 |
+
position: fixed;
|
34 |
+
top: 0;
|
35 |
+
left: 0;
|
36 |
+
width: 100%;
|
37 |
+
height: 100%;
|
38 |
+
background:
|
39 |
+
radial-gradient(circle at 20% 30%, #ff0066 0px, transparent 100px),
|
40 |
+
radial-gradient(circle at 80% 70%, #00ffff 0px, transparent 100px),
|
41 |
+
radial-gradient(circle at 50% 50%, #ffff00 0px, transparent 150px),
|
42 |
+
radial-gradient(circle at 30% 80%, #ff00ff 0px, transparent 80px),
|
43 |
+
radial-gradient(circle at 70% 20%, #00ff00 0px, transparent 90px);
|
44 |
+
opacity: 0.1;
|
45 |
+
z-index: 0;
|
46 |
+
animation: casinoLights 10s ease-in-out infinite;
|
47 |
+
}
|
48 |
+
|
49 |
+
@keyframes casinoLights {
|
50 |
+
0%, 100% { filter: hue-rotate(0deg) brightness(1); }
|
51 |
+
50% { filter: hue-rotate(180deg) brightness(1.5); }
|
52 |
+
}
|
53 |
+
|
54 |
+
/* Static TV noise overlay */
|
55 |
+
body::after {
|
56 |
content: '';
|
57 |
position: fixed;
|
58 |
top: 0;
|
|
|
73 |
rgba(0,0,0,0.05) 1px,
|
74 |
transparent 1px,
|
75 |
transparent 2px
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
);
|
77 |
+
background-size: 2px 2px, 2px 2px;
|
78 |
pointer-events: none;
|
79 |
z-index: 1;
|
80 |
opacity: 0.8;
|
81 |
animation: staticNoise 0.1s steps(8) infinite;
|
82 |
}
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
@keyframes staticNoise {
|
85 |
0%, 100% { transform: translate(0, 0); }
|
86 |
+
50% { transform: translate(-1px, -1px); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
|
89 |
+
/* Main casino cabinet */
|
90 |
.machine-container {
|
91 |
+
background: linear-gradient(145deg, #1a0000, #330000);
|
92 |
+
border: 5px solid #ffd700;
|
93 |
+
border-radius: 30px;
|
94 |
+
padding: 20px;
|
95 |
+
padding-right: 120px;
|
96 |
+
box-shadow:
|
97 |
+
0 0 50px rgba(255, 215, 0, 0.5),
|
98 |
+
0 20px 40px rgba(0,0,0,0.8),
|
99 |
+
inset 0 0 30px rgba(255, 215, 0, 0.2);
|
100 |
width: 95vw;
|
101 |
max-width: 1400px;
|
102 |
position: relative;
|
103 |
z-index: 2;
|
104 |
}
|
105 |
|
106 |
+
/* Blinking lights around the machine */
|
107 |
+
.machine-container::before {
|
108 |
+
content: '';
|
109 |
+
position: absolute;
|
110 |
+
top: -10px;
|
111 |
+
left: -10px;
|
112 |
+
right: -10px;
|
113 |
+
bottom: -10px;
|
114 |
+
border-radius: 35px;
|
115 |
+
background: conic-gradient(
|
116 |
+
from 0deg,
|
117 |
+
#ff0000, #ff7700, #ffff00, #00ff00,
|
118 |
+
#0000ff, #ff00ff, #ff0000
|
119 |
+
);
|
120 |
+
z-index: -1;
|
121 |
+
animation: rotateGradient 3s linear infinite;
|
122 |
+
filter: blur(10px);
|
123 |
+
opacity: 0.7;
|
124 |
+
}
|
125 |
+
|
126 |
+
@keyframes rotateGradient {
|
127 |
+
0% { transform: rotate(0deg); }
|
128 |
+
100% { transform: rotate(360deg); }
|
129 |
+
}
|
130 |
+
|
131 |
+
/* Neon title */
|
132 |
.title {
|
133 |
text-align: center;
|
134 |
+
font-family: 'Bebas Neue', cursive;
|
135 |
+
font-size: 4rem;
|
136 |
+
margin-bottom: 10px;
|
137 |
+
position: relative;
|
138 |
+
text-transform: uppercase;
|
139 |
+
letter-spacing: 0.2em;
|
140 |
}
|
141 |
|
142 |
.title a {
|
143 |
text-decoration: none;
|
144 |
+
color: #fff;
|
145 |
+
text-shadow:
|
146 |
+
0 0 10px #ff00ff,
|
147 |
+
0 0 20px #ff00ff,
|
148 |
+
0 0 30px #ff00ff,
|
149 |
+
0 0 40px #ff00ff,
|
150 |
+
0 0 70px #ff00ff,
|
151 |
+
0 0 80px #ff00ff,
|
152 |
+
0 0 100px #ff00ff,
|
153 |
+
0 0 150px #ff00ff;
|
154 |
+
animation: neonFlicker 1.5s infinite alternate;
|
155 |
}
|
156 |
|
157 |
+
@keyframes neonFlicker {
|
158 |
+
0%, 100% { opacity: 1; }
|
159 |
+
33% { opacity: 0.8; }
|
160 |
+
66% { opacity: 0.9; }
|
161 |
}
|
162 |
|
163 |
+
.subtitle {
|
164 |
+
text-align: center;
|
165 |
+
font-size: 1.5rem;
|
166 |
+
color: #ffd700;
|
167 |
+
margin-bottom: 20px;
|
168 |
+
text-shadow: 0 0 10px #ffd700;
|
169 |
+
animation: pulse 2s ease-in-out infinite;
|
170 |
+
}
|
171 |
+
|
172 |
+
@keyframes pulse {
|
173 |
+
0%, 100% { transform: scale(1); }
|
174 |
+
50% { transform: scale(1.05); }
|
175 |
+
}
|
176 |
+
|
177 |
+
/* Jackpot counter */
|
178 |
+
.jackpot-display {
|
179 |
+
background: #000;
|
180 |
+
border: 3px solid #ffd700;
|
181 |
+
border-radius: 10px;
|
182 |
+
padding: 10px 20px;
|
183 |
+
margin: 10px auto;
|
184 |
+
text-align: center;
|
185 |
+
max-width: 400px;
|
186 |
+
box-shadow:
|
187 |
+
inset 0 0 20px rgba(255, 215, 0, 0.3),
|
188 |
+
0 0 20px rgba(255, 215, 0, 0.5);
|
189 |
+
}
|
190 |
+
|
191 |
+
.jackpot-label {
|
192 |
+
font-size: 0.9rem;
|
193 |
+
color: #ffd700;
|
194 |
+
text-transform: uppercase;
|
195 |
+
letter-spacing: 2px;
|
196 |
+
}
|
197 |
+
|
198 |
+
.jackpot-value {
|
199 |
+
font-size: 2rem;
|
200 |
+
color: #00ff00;
|
201 |
+
font-weight: bold;
|
202 |
+
text-shadow: 0 0 10px #00ff00;
|
203 |
+
font-family: 'Orbitron', monospace;
|
204 |
+
}
|
205 |
+
|
206 |
+
/* Cell type selector with casino chips style */
|
207 |
.cell-type-selector {
|
208 |
display: flex;
|
209 |
align-items: center;
|
210 |
justify-content: center;
|
211 |
gap: 20px;
|
212 |
+
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
213 |
}
|
214 |
|
215 |
.radio-group {
|
216 |
display: flex;
|
217 |
+
gap: 30px;
|
218 |
}
|
219 |
|
220 |
+
.chip-label {
|
221 |
+
position: relative;
|
222 |
display: flex;
|
223 |
align-items: center;
|
224 |
+
justify-content: center;
|
225 |
+
width: 100px;
|
226 |
+
height: 100px;
|
227 |
cursor: pointer;
|
228 |
+
transition: all 0.3s ease;
|
229 |
+
}
|
230 |
+
|
231 |
+
.chip-label input[type="radio"] {
|
232 |
+
position: absolute;
|
233 |
+
opacity: 0;
|
234 |
+
}
|
235 |
+
|
236 |
+
.chip {
|
237 |
+
position: relative;
|
238 |
+
width: 100%;
|
239 |
+
height: 100%;
|
240 |
+
border-radius: 50%;
|
241 |
+
background: radial-gradient(circle at 30% 30%, #ff4444, #cc0000);
|
242 |
+
box-shadow:
|
243 |
+
0 5px 15px rgba(0,0,0,0.5),
|
244 |
+
inset 0 0 20px rgba(0,0,0,0.3),
|
245 |
+
inset -3px -3px 10px rgba(255,255,255,0.2);
|
246 |
+
display: flex;
|
247 |
+
align-items: center;
|
248 |
+
justify-content: center;
|
249 |
+
font-weight: bold;
|
250 |
font-size: 1.1rem;
|
251 |
color: #fff;
|
252 |
+
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
|
253 |
+
border: 8px dashed #fff;
|
254 |
+
animation: chipRotate 20s linear infinite;
|
255 |
}
|
256 |
|
257 |
+
@keyframes chipRotate {
|
258 |
+
0% { transform: rotate(0deg); }
|
259 |
+
100% { transform: rotate(360deg); }
|
260 |
}
|
261 |
|
262 |
+
.chip-label:hover .chip {
|
263 |
+
transform: scale(1.1);
|
264 |
+
box-shadow:
|
265 |
+
0 10px 30px rgba(255,0,0,0.5),
|
266 |
+
inset 0 0 30px rgba(255,255,255,0.3);
|
267 |
+
}
|
268 |
+
|
269 |
+
.chip-label input[type="radio"]:checked + .chip {
|
270 |
+
background: radial-gradient(circle at 30% 30%, #44ff44, #00cc00);
|
271 |
+
box-shadow:
|
272 |
+
0 0 30px rgba(0,255,0,0.7),
|
273 |
+
inset 0 0 20px rgba(0,0,0,0.3);
|
274 |
+
animation: chipRotate 5s linear infinite, winPulse 1s ease-in-out infinite;
|
275 |
}
|
276 |
|
277 |
+
@keyframes winPulse {
|
278 |
+
0%, 100% { transform: scale(1); }
|
279 |
+
50% { transform: scale(1.05); }
|
280 |
+
}
|
281 |
+
|
282 |
+
/* Slot machine reels */
|
283 |
.reels-container {
|
284 |
background: #000;
|
285 |
+
border: 5px solid #ffd700;
|
286 |
+
border-radius: 15px;
|
287 |
+
padding: 20px;
|
288 |
max-width: 100%;
|
289 |
position: relative;
|
290 |
+
box-shadow:
|
291 |
+
inset 0 0 50px rgba(0,0,0,0.8),
|
292 |
+
0 0 30px rgba(255, 215, 0, 0.5);
|
293 |
overflow: visible;
|
294 |
+
margin: 20px 0;
|
295 |
}
|
296 |
|
297 |
.reels-wrapper {
|
298 |
display: flex;
|
299 |
+
gap: 2px;
|
300 |
min-width: fit-content;
|
301 |
+
padding: 5px 0;
|
302 |
justify-content: center;
|
303 |
flex-wrap: wrap;
|
304 |
max-width: 1200px;
|
305 |
margin: 0 auto;
|
306 |
+
background: linear-gradient(90deg,
|
307 |
+
transparent 0%,
|
308 |
+
rgba(255, 215, 0, 0.1) 50%,
|
309 |
+
transparent 100%);
|
310 |
}
|
311 |
|
312 |
.reel {
|
313 |
+
width: 20px;
|
314 |
+
height: 50px;
|
315 |
background: #ffffff;
|
316 |
+
border: 2px solid #ffd700;
|
317 |
+
border-radius: 3px;
|
318 |
overflow: hidden;
|
319 |
position: relative;
|
320 |
+
box-shadow:
|
321 |
+
inset 0 0 10px rgba(0,0,0,0.3),
|
322 |
+
0 0 5px rgba(255, 215, 0, 0.5);
|
323 |
}
|
324 |
|
325 |
.reel-strip {
|
|
|
329 |
}
|
330 |
|
331 |
.nucleotide {
|
332 |
+
height: 50px;
|
333 |
display: flex;
|
334 |
align-items: center;
|
335 |
justify-content: center;
|
336 |
+
font-size: 1.2rem;
|
337 |
font-weight: bold;
|
338 |
background: #ffffff;
|
339 |
+
text-shadow: 0 0 5px currentColor;
|
340 |
}
|
341 |
|
342 |
+
.nucleotide.A { color: #00ff00; background: #001100; }
|
343 |
+
.nucleotide.T { color: #ff0000; background: #110000; }
|
344 |
+
.nucleotide.C { color: #00ffff; background: #001111; }
|
345 |
+
.nucleotide.G { color: #ffff00; background: #111100; }
|
346 |
|
347 |
+
/* Casino style lever */
|
348 |
+
.lever-container {
|
349 |
+
position: absolute;
|
350 |
+
right: -90px;
|
351 |
+
top: 50%;
|
352 |
+
transform: translateY(-50%);
|
353 |
+
z-index: 3;
|
354 |
+
width: 80px;
|
355 |
+
height: 250px;
|
356 |
}
|
357 |
|
358 |
+
.lever {
|
359 |
+
width: 100%;
|
360 |
+
height: 100%;
|
361 |
+
position: relative;
|
362 |
+
cursor: pointer;
|
363 |
+
}
|
364 |
+
|
365 |
+
.lever-mount {
|
366 |
+
position: absolute;
|
367 |
+
top: 100px;
|
368 |
+
left: -15px;
|
369 |
+
width: 60px;
|
370 |
+
height: 80px;
|
371 |
+
background: linear-gradient(180deg, #ffd700, #b8860b);
|
372 |
+
border-radius: 10px 0 0 10px;
|
373 |
+
box-shadow:
|
374 |
+
0 5px 20px rgba(0,0,0,0.5),
|
375 |
+
inset 0 2px 5px rgba(255,255,255,0.5);
|
376 |
+
}
|
377 |
+
|
378 |
+
.lever-arm {
|
379 |
+
position: absolute;
|
380 |
+
top: 30px;
|
381 |
+
left: 10px;
|
382 |
+
width: 15px;
|
383 |
+
height: 100px;
|
384 |
+
background: linear-gradient(180deg, #c0c0c0, #808080);
|
385 |
+
border-radius: 8px;
|
386 |
+
box-shadow: 0 3px 10px rgba(0,0,0,0.5);
|
387 |
+
transition: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
388 |
+
}
|
389 |
+
|
390 |
+
.lever-ball {
|
391 |
+
position: absolute;
|
392 |
+
top: -40px;
|
393 |
+
left: 50%;
|
394 |
+
transform: translateX(-50%);
|
395 |
+
width: 80px;
|
396 |
+
height: 80px;
|
397 |
+
background: radial-gradient(circle at 35% 35%, #ff4444, #cc0000, #800000);
|
398 |
+
border-radius: 50%;
|
399 |
+
box-shadow:
|
400 |
+
0 10px 30px rgba(0,0,0,0.6),
|
401 |
+
inset -10px -10px 20px rgba(0,0,0,0.5),
|
402 |
+
inset 5px 5px 10px rgba(255,255,255,0.6);
|
403 |
+
position: relative;
|
404 |
+
overflow: hidden;
|
405 |
+
}
|
406 |
+
|
407 |
+
.lever-ball::before {
|
408 |
+
content: '777';
|
409 |
+
position: absolute;
|
410 |
+
top: 50%;
|
411 |
+
left: 50%;
|
412 |
+
transform: translate(-50%, -50%);
|
413 |
font-size: 1.5rem;
|
414 |
font-weight: bold;
|
415 |
+
color: #ffd700;
|
416 |
+
text-shadow: 0 2px 4px rgba(0,0,0,0.8);
|
417 |
+
}
|
418 |
+
|
419 |
+
.lever.pulled .lever-arm {
|
420 |
+
transform: translateY(100px);
|
421 |
+
height: 20px;
|
422 |
+
}
|
423 |
+
|
424 |
+
/* Generate button */
|
425 |
+
.spin-button {
|
426 |
+
background: linear-gradient(145deg, #ff0000, #cc0000);
|
427 |
+
border: 3px solid #ffd700;
|
428 |
+
padding: 25px 80px;
|
429 |
+
font-size: 2rem;
|
430 |
+
font-weight: bold;
|
431 |
border-radius: 50px;
|
432 |
cursor: pointer;
|
433 |
text-transform: uppercase;
|
434 |
+
letter-spacing: 3px;
|
435 |
+
box-shadow:
|
436 |
+
0 10px 30px rgba(0,0,0,0.7),
|
437 |
+
0 0 30px rgba(255, 0, 0, 0.5),
|
438 |
+
inset 0 2px 10px rgba(255,255,255,0.3);
|
439 |
transition: all 0.3s ease;
|
440 |
color: #fff;
|
441 |
+
text-shadow: 0 3px 6px rgba(0,0,0,0.5);
|
442 |
position: relative;
|
443 |
overflow: hidden;
|
444 |
+
font-family: 'Bebas Neue', cursive;
|
445 |
}
|
446 |
|
447 |
.spin-button::before {
|
448 |
content: '';
|
449 |
position: absolute;
|
450 |
+
top: -50%;
|
451 |
+
left: -50%;
|
452 |
+
width: 200%;
|
453 |
+
height: 200%;
|
454 |
+
background: linear-gradient(45deg,
|
455 |
+
transparent 30%,
|
456 |
+
rgba(255,255,255,0.3) 50%,
|
457 |
+
transparent 70%);
|
458 |
+
animation: buttonShine 3s infinite;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
}
|
460 |
|
461 |
+
@keyframes buttonShine {
|
462 |
+
0% { transform: rotate(0deg); }
|
463 |
+
100% { transform: rotate(360deg); }
|
|
|
464 |
}
|
465 |
|
466 |
+
.spin-button:hover {
|
467 |
+
transform: translateY(-3px) scale(1.05);
|
468 |
+
box-shadow:
|
469 |
+
0 15px 40px rgba(0,0,0,0.8),
|
470 |
+
0 0 50px rgba(255, 0, 0, 0.7);
|
471 |
}
|
472 |
|
473 |
.spin-button:active {
|
474 |
+
transform: translateY(0) scale(0.98);
|
475 |
}
|
476 |
|
477 |
.spin-button:disabled {
|
478 |
+
background: linear-gradient(145deg, #444, #222);
|
479 |
cursor: not-allowed;
|
480 |
box-shadow: none;
|
481 |
+
animation: none;
|
482 |
}
|
483 |
|
484 |
+
/* Sequence display */
|
485 |
.sequence-display {
|
486 |
+
background: #000;
|
487 |
+
border: 3px solid #00ff00;
|
488 |
+
border-radius: 15px;
|
489 |
+
padding: 25px;
|
490 |
+
font-family: 'Orbitron', monospace;
|
491 |
font-size: 0.9rem;
|
492 |
+
letter-spacing: 2px;
|
493 |
width: 100%;
|
494 |
max-width: 1200px;
|
495 |
+
margin: 20px auto;
|
496 |
+
box-shadow:
|
497 |
+
0 0 30px rgba(0, 255, 0, 0.5),
|
498 |
+
inset 0 0 20px rgba(0, 255, 0, 0.1);
|
499 |
position: relative;
|
500 |
+
min-height: 100px;
|
501 |
}
|
502 |
|
503 |
.sequence-display::before {
|
504 |
+
content: '𧬠SYNTHETIC REGULATORY ELEMENT';
|
505 |
position: absolute;
|
506 |
+
top: -15px;
|
507 |
left: 50%;
|
508 |
transform: translateX(-50%);
|
509 |
+
background: #000;
|
510 |
+
padding: 0 20px;
|
511 |
+
font-size: 0.8rem;
|
512 |
+
color: #00ff00;
|
513 |
+
letter-spacing: 3px;
|
514 |
+
text-shadow: 0 0 10px #00ff00;
|
515 |
}
|
516 |
|
517 |
+
/* Protein analysis panel */
|
518 |
+
.protein-panel {
|
519 |
+
background: linear-gradient(145deg, #1a0033, #000033);
|
520 |
+
border: 3px solid #00ffff;
|
521 |
+
border-radius: 15px;
|
522 |
+
padding: 25px;
|
523 |
+
margin: 20px auto;
|
524 |
+
max-width: 1200px;
|
525 |
+
box-shadow:
|
526 |
+
0 0 30px rgba(0, 255, 255, 0.5),
|
527 |
+
inset 0 0 20px rgba(0, 255, 255, 0.1);
|
528 |
+
display: none;
|
529 |
+
animation: fadeIn 0.5s ease-in;
|
530 |
}
|
531 |
|
532 |
+
@keyframes fadeIn {
|
533 |
+
from { opacity: 0; transform: translateY(20px); }
|
534 |
+
to { opacity: 1; transform: translateY(0); }
|
535 |
+
}
|
536 |
+
|
537 |
+
.protein-panel.active {
|
538 |
+
display: block;
|
539 |
+
}
|
540 |
+
|
541 |
+
.protein-header {
|
542 |
+
font-size: 1.5rem;
|
543 |
+
color: #00ffff;
|
544 |
+
margin-bottom: 15px;
|
545 |
text-align: center;
|
546 |
+
text-transform: uppercase;
|
547 |
+
letter-spacing: 3px;
|
548 |
+
text-shadow: 0 0 15px #00ffff;
|
549 |
}
|
550 |
|
551 |
+
.protein-sequence {
|
552 |
+
background: #000;
|
553 |
+
border: 1px solid #00ffff;
|
554 |
+
border-radius: 10px;
|
555 |
+
padding: 15px;
|
556 |
+
margin-bottom: 20px;
|
557 |
+
font-family: 'Courier New', monospace;
|
558 |
+
font-size: 0.85rem;
|
559 |
+
word-break: break-all;
|
560 |
+
color: #00ff00;
|
561 |
+
max-height: 150px;
|
562 |
+
overflow-y: auto;
|
563 |
}
|
564 |
|
565 |
+
.protein-analysis {
|
566 |
+
background: rgba(0, 255, 255, 0.05);
|
567 |
+
border: 1px solid rgba(0, 255, 255, 0.3);
|
568 |
+
border-radius: 10px;
|
569 |
+
padding: 20px;
|
570 |
color: #fff;
|
571 |
+
line-height: 1.8;
|
572 |
+
font-size: 0.95rem;
|
|
|
573 |
}
|
574 |
|
575 |
+
.protein-analysis h3 {
|
576 |
+
color: #00ffff;
|
577 |
+
margin-bottom: 10px;
|
578 |
+
text-shadow: 0 0 10px #00ffff;
|
579 |
}
|
580 |
|
581 |
+
.protein-stats {
|
582 |
+
display: grid;
|
583 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
584 |
+
gap: 15px;
|
585 |
+
margin-bottom: 20px;
|
586 |
}
|
587 |
|
588 |
+
.stat-card {
|
589 |
+
background: rgba(255, 215, 0, 0.1);
|
590 |
+
border: 1px solid #ffd700;
|
591 |
+
border-radius: 10px;
|
592 |
+
padding: 15px;
|
593 |
+
text-align: center;
|
594 |
}
|
595 |
|
596 |
+
.stat-label {
|
597 |
+
font-size: 0.8rem;
|
598 |
+
color: #ffd700;
|
599 |
+
text-transform: uppercase;
|
600 |
+
letter-spacing: 1px;
|
601 |
}
|
602 |
|
603 |
+
.stat-value {
|
604 |
+
font-size: 1.5rem;
|
605 |
+
color: #fff;
|
606 |
+
font-weight: bold;
|
607 |
+
margin-top: 5px;
|
|
|
|
|
|
|
608 |
}
|
609 |
|
610 |
+
/* Info footer */
|
611 |
+
.info {
|
612 |
+
text-align: center;
|
613 |
+
margin-top: 20px;
|
614 |
+
color: #ffd700;
|
615 |
+
font-size: 1rem;
|
616 |
+
text-transform: uppercase;
|
617 |
+
letter-spacing: 2px;
|
618 |
+
text-shadow: 0 0 10px #ffd700;
|
619 |
}
|
620 |
|
621 |
+
.lab-credit {
|
622 |
+
text-align: center;
|
623 |
+
margin-top: 15px;
|
624 |
+
font-size: 1.3rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
625 |
}
|
626 |
|
627 |
+
.lab-credit a {
|
628 |
+
color: #00ff00;
|
629 |
+
text-decoration: none;
|
630 |
+
font-weight: bold;
|
631 |
+
letter-spacing: 2px;
|
632 |
+
padding: 10px 30px;
|
633 |
+
border: 2px solid #00ff00;
|
634 |
+
border-radius: 30px;
|
635 |
+
display: inline-block;
|
636 |
+
transition: all 0.3s ease;
|
637 |
+
text-shadow: 0 0 10px #00ff00;
|
638 |
}
|
639 |
|
640 |
+
.lab-credit a:hover {
|
641 |
+
background: #00ff00;
|
642 |
+
color: #000;
|
643 |
+
box-shadow: 0 0 30px #00ff00;
|
644 |
+
transform: scale(1.1);
|
|
|
|
|
|
|
|
|
|
|
645 |
}
|
646 |
|
647 |
+
/* Winning animation */
|
648 |
+
.jackpot-win {
|
649 |
+
animation: jackpotFlash 2s ease-out;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
650 |
}
|
651 |
|
652 |
+
@keyframes jackpotFlash {
|
653 |
+
0%, 100% { background-color: transparent; }
|
654 |
+
10%, 30%, 50%, 70%, 90% { background-color: rgba(255, 215, 0, 0.3); }
|
655 |
+
20%, 40%, 60%, 80% { background-color: transparent; }
|
656 |
}
|
657 |
|
658 |
+
/* Loading animation */
|
659 |
@keyframes continuousSpin {
|
660 |
from { transform: translateY(0); }
|
661 |
+
to { transform: translateY(-200px); }
|
662 |
}
|
663 |
|
664 |
.reel-strip.loading {
|
665 |
animation: continuousSpin 1s linear infinite;
|
666 |
}
|
667 |
+
|
668 |
+
/* Scrollbar styling */
|
669 |
+
::-webkit-scrollbar {
|
670 |
+
width: 10px;
|
671 |
+
}
|
672 |
+
|
673 |
+
::-webkit-scrollbar-track {
|
674 |
+
background: rgba(0, 0, 0, 0.5);
|
675 |
+
border-radius: 5px;
|
676 |
+
}
|
677 |
+
|
678 |
+
::-webkit-scrollbar-thumb {
|
679 |
+
background: #00ffff;
|
680 |
+
border-radius: 5px;
|
681 |
+
}
|
682 |
+
|
683 |
+
::-webkit-scrollbar-thumb:hover {
|
684 |
+
background: #00cccc;
|
685 |
+
}
|
686 |
</style>
|
687 |
</head>
|
688 |
<body>
|
689 |
<div class="machine-container">
|
690 |
+
<h1 class="title"><a href="https://github.com/pinellolab/DNA-Diffusion" target="_blank" rel="noopener noreferrer">π° DNA CASINO π§¬</a></h1>
|
691 |
+
<div class="subtitle">β
PROTEIN SYNTHESIS JACKPOT β
</div>
|
692 |
+
|
693 |
+
<div class="jackpot-display">
|
694 |
+
<div class="jackpot-label">Current Sequence Length</div>
|
695 |
+
<div class="jackpot-value" id="sequenceCounter">0 BP</div>
|
696 |
+
</div>
|
697 |
|
698 |
<div class="cell-type-selector">
|
|
|
699 |
<div class="radio-group">
|
700 |
+
<label class="chip-label">
|
701 |
<input type="radio" name="cellType" value="K562" checked>
|
702 |
+
<div class="chip">K562</div>
|
703 |
</label>
|
704 |
+
<label class="chip-label">
|
705 |
<input type="radio" name="cellType" value="GM12878">
|
706 |
+
<div class="chip">GM12878</div>
|
707 |
</label>
|
708 |
+
<label class="chip-label">
|
709 |
<input type="radio" name="cellType" value="HepG2">
|
710 |
+
<div class="chip">HepG2</div>
|
711 |
</label>
|
712 |
</div>
|
713 |
</div>
|
|
|
716 |
<div class="reels-wrapper" id="reelsWrapper"></div>
|
717 |
<div class="lever-container">
|
718 |
<div class="lever" id="lever">
|
719 |
+
<div class="lever-mount"></div>
|
|
|
|
|
720 |
<div class="lever-arm">
|
721 |
<div class="lever-ball"></div>
|
722 |
</div>
|
|
|
725 |
</div>
|
726 |
|
727 |
<div class="controls">
|
728 |
+
<button class="spin-button" id="spinButton"><span>π² SPIN TO WIN π²</span></button>
|
729 |
+
|
730 |
<div class="sequence-display" id="sequenceDisplay">
|
731 |
+
π― Pull the lever or press SPIN to generate your winning sequence! π―
|
732 |
+
</div>
|
733 |
+
|
734 |
+
<div class="protein-panel" id="proteinPanel">
|
735 |
+
<div class="protein-header">π¬ Protein Analysis Report π¬</div>
|
736 |
+
|
737 |
+
<div class="protein-stats" id="proteinStats"></div>
|
738 |
+
|
739 |
+
<div class="protein-sequence" id="proteinSequence"></div>
|
740 |
+
|
741 |
+
<div class="protein-analysis" id="proteinAnalysis">
|
742 |
+
<h3>Analyzing protein structure...</h3>
|
743 |
+
</div>
|
744 |
</div>
|
745 |
</div>
|
746 |
|
747 |
<div class="info">
|
748 |
+
π° 200BP REGULATORY ELEMENTS β’ CELL-TYPE SPECIFIC β’ SYNTHETIC BIOLOGY JACKPOT π°
|
749 |
</div>
|
750 |
|
751 |
<div class="lab-credit">
|
752 |
<a href="https://pinellolab.org" target="_blank" rel="noopener noreferrer">
|
753 |
+
π PINELLO LAB π
|
754 |
</a>
|
755 |
</div>
|
756 |
</div>
|
|
|
804 |
|
805 |
// Set initial position to show a random nucleotide
|
806 |
const randomIndex = Math.floor(Math.random() * 4);
|
807 |
+
const initialOffset = -randomIndex * 50;
|
808 |
reel.strip.style.transform = `translateY(${initialOffset}px)`;
|
809 |
+
reel.currentPosition = randomIndex * 50;
|
810 |
}
|
811 |
}
|
812 |
|
813 |
+
function updateSequenceCounter(length) {
|
814 |
+
const counter = document.getElementById('sequenceCounter');
|
815 |
+
counter.textContent = `${length} BP`;
|
816 |
+
counter.style.animation = 'pulse 0.5s ease-out';
|
817 |
+
}
|
818 |
+
|
819 |
function startContinuousSpinning() {
|
820 |
reels.forEach((reel, index) => {
|
821 |
// Add continuous spinning animation
|
|
|
826 |
const delay = (index % 10) * 0.1;
|
827 |
reel.strip.style.animationDelay = `${delay}s`;
|
828 |
});
|
829 |
+
|
830 |
+
// Update counter animation
|
831 |
+
let count = 0;
|
832 |
+
const counterInterval = setInterval(() => {
|
833 |
+
if (!isSpinning) {
|
834 |
+
clearInterval(counterInterval);
|
835 |
+
return;
|
836 |
+
}
|
837 |
+
count = (count + 7) % 201;
|
838 |
+
updateSequenceCounter(count);
|
839 |
+
}, 100);
|
840 |
}
|
841 |
|
842 |
+
function displayProteinAnalysis(metadata) {
|
843 |
+
const panel = document.getElementById('proteinPanel');
|
844 |
+
const statsDiv = document.getElementById('proteinStats');
|
845 |
+
const sequenceDiv = document.getElementById('proteinSequence');
|
846 |
+
const analysisDiv = document.getElementById('proteinAnalysis');
|
847 |
+
|
848 |
+
// Show panel
|
849 |
+
panel.classList.add('active');
|
850 |
+
|
851 |
+
// Display stats
|
852 |
+
statsDiv.innerHTML = `
|
853 |
+
<div class="stat-card">
|
854 |
+
<div class="stat-label">Cell Type</div>
|
855 |
+
<div class="stat-value">${metadata.cell_type || 'Unknown'}</div>
|
856 |
+
</div>
|
857 |
+
<div class="stat-card">
|
858 |
+
<div class="stat-label">DNA Length</div>
|
859 |
+
<div class="stat-value">${TARGET_SEQUENCE.length} bp</div>
|
860 |
+
</div>
|
861 |
+
<div class="stat-card">
|
862 |
+
<div class="stat-label">Protein Length</div>
|
863 |
+
<div class="stat-value">${metadata.protein_length || 0} aa</div>
|
864 |
+
</div>
|
865 |
+
<div class="stat-card">
|
866 |
+
<div class="stat-label">Generation Time</div>
|
867 |
+
<div class="stat-value">${(metadata.generation_time || 0).toFixed(1)}s</div>
|
868 |
+
</div>
|
869 |
+
`;
|
870 |
+
|
871 |
+
// Display protein sequence
|
872 |
+
if (metadata.protein_sequence) {
|
873 |
+
sequenceDiv.innerHTML = `<strong>Protein Sequence:</strong><br>${metadata.protein_sequence}`;
|
874 |
+
}
|
875 |
+
|
876 |
+
// Display analysis
|
877 |
+
if (metadata.protein_analysis) {
|
878 |
+
analysisDiv.innerHTML = `<h3>𧬠Structural & Functional Analysis</h3>${metadata.protein_analysis}`;
|
879 |
+
} else {
|
880 |
+
analysisDiv.innerHTML = '<h3>β³ Protein analysis pending...</h3>';
|
881 |
+
}
|
882 |
+
}
|
883 |
+
|
884 |
+
function stopAndShowSequence(sequence, metadata = {}) {
|
885 |
TARGET_SEQUENCE = sequence;
|
886 |
+
updateSequenceCounter(sequence.length);
|
887 |
|
888 |
reels.forEach((reel, index) => {
|
889 |
// Remove continuous spinning
|
|
|
892 |
// Calculate target position
|
893 |
const targetNucleotide = TARGET_SEQUENCE[index];
|
894 |
const targetIndex = NUCLEOTIDES.indexOf(targetNucleotide);
|
895 |
+
const finalPosition = targetIndex * 50;
|
896 |
|
897 |
// Set up the final positioning animation
|
898 |
setTimeout(() => {
|
|
|
910 |
const lever = document.getElementById('lever');
|
911 |
|
912 |
container.classList.remove('spinning');
|
913 |
+
container.classList.add('jackpot-win');
|
914 |
+
|
915 |
+
display.innerHTML = `<strong>π JACKPOT SEQUENCE π</strong><br><span style="color: #00ff00; font-family: 'Courier New', monospace;">${TARGET_SEQUENCE}</span>`;
|
916 |
+
|
917 |
+
// Display protein analysis if available
|
918 |
+
if (metadata) {
|
919 |
+
displayProteinAnalysis(metadata);
|
920 |
+
}
|
921 |
|
|
|
922 |
button.disabled = false;
|
923 |
isSpinning = false;
|
924 |
|
|
|
926 |
lever.classList.remove('pulled');
|
927 |
|
928 |
setTimeout(() => {
|
929 |
+
container.classList.remove('jackpot-win');
|
930 |
+
}, 2000);
|
931 |
}, 1500);
|
932 |
}
|
933 |
|
|
|
939 |
const display = document.getElementById('sequenceDisplay');
|
940 |
const container = document.getElementById('reelsContainer');
|
941 |
const lever = document.getElementById('lever');
|
942 |
+
const proteinPanel = document.getElementById('proteinPanel');
|
943 |
+
|
944 |
+
// Hide protein panel from previous spin
|
945 |
+
proteinPanel.classList.remove('active');
|
946 |
|
947 |
// Pull the lever
|
948 |
lever.classList.add('pulled');
|
949 |
|
950 |
button.disabled = true;
|
951 |
+
display.innerHTML = 'π² <strong>SPINNING THE GENETIC WHEEL OF FORTUNE...</strong> π²';
|
952 |
container.classList.add('spinning');
|
953 |
|
954 |
// Start continuous spinning immediately
|
|
|
980 |
// Listen for messages from parent window
|
981 |
window.addEventListener('message', (event) => {
|
982 |
if (event.data.type === 'sequence_generated') {
|
983 |
+
// Stop spinning and show the actual sequence with metadata
|
984 |
+
stopAndShowSequence(event.data.sequence, event.data.metadata);
|
985 |
} else if (event.data.type === 'generation_error') {
|
986 |
// Stop spinning and show error
|
987 |
reels.forEach(reel => {
|
|
|
994 |
const lever = document.getElementById('lever');
|
995 |
|
996 |
container.classList.remove('spinning');
|
997 |
+
display.innerHTML = '<strong style="color: #ff0000;">β BUST! β</strong><br>' + event.data.error;
|
998 |
button.disabled = false;
|
999 |
isSpinning = false;
|
1000 |
lever.classList.remove('pulled');
|
1001 |
+
updateSequenceCounter(0);
|
1002 |
}
|
1003 |
});
|
1004 |
|
|
|
1009 |
startGeneration();
|
1010 |
}
|
1011 |
});
|
1012 |
+
|
1013 |
+
// Add some casino ambiance
|
1014 |
+
setInterval(() => {
|
1015 |
+
if (!isSpinning && Math.random() > 0.7) {
|
1016 |
+
const chips = document.querySelectorAll('.chip');
|
1017 |
+
const randomChip = chips[Math.floor(Math.random() * chips.length)];
|
1018 |
+
randomChip.style.animation = 'none';
|
1019 |
+
setTimeout(() => {
|
1020 |
+
randomChip.style.animation = 'chipRotate 20s linear infinite';
|
1021 |
+
}, 10);
|
1022 |
+
}
|
1023 |
+
}, 5000);
|
1024 |
</script>
|
1025 |
</body>
|
1026 |
</html>
|