├── CNAME
├── LICENSE
├── README.md
├── about.html
├── index.css
├── index.html
└── index.js
/CNAME:
--------------------------------------------------------------------------------
1 | isthisheadlinefake.com
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 TristanMenzinger & Robin Weitzel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Is this Headline Fake or Not?
2 |
3 | We live in crazy times - but can you tell how crazy? Visit [isthisheadlinefake.com](https://isthisheadlinefake.com) to find out.
4 |
5 |
6 |
7 | ### Why
8 | We made this to show two things:
9 | * Neural networks have become incredibly good at producing grammatically correct but completely nonsensical text
10 | * There are so many nonsensical headlines nowadays, it's hard to distinguish fake from real
11 |
12 | ### How
13 | * We trained the network on 200'000 real headlines from the [Huffington Post](https://www.huffpost.com)
14 | using OpenAI's [GPT-2](https://github.com/openai/gpt-2!). If you want to experiment yourself, you can find the dataset [here](https://www.kaggle.com/rmisra/news-category-dataset).
15 | * Hosted on Github Pages using Cloudflare Workers & Key-Value store. Using native CSS transforms for the animations.
16 |
17 |
18 | ### Who
19 | Made by [Robin Weitzel](https://github.com/RobinWeitzel) and [Tristan Menzinger](https://github.com/TristanMenzinger).
20 |
21 | ### Disclaimer
22 | Half of the headlines are from the Huffington Post, the other half is machine generated. We do not claim authenticity for any of these headlines. The headlines are posted for comedic purposes only and not meant to attack anyone. If you find a headline offensive please get in touch via GitHub.
23 |
--------------------------------------------------------------------------------
/about.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
99 |
100 |
101 |
102 |
Is this Headline
103 | fake or not ?
104 |
105 |
106 |
DISCLAIMER
107 |
108 | Half of the headlines are from the Huffington Post, the other half is machine generated.
109 | We do not claim authenticity for any of these headlines.
110 | The headlines are posted for comedic purposes and not meant to attack anyone.
111 | If you find a headline offensive please get in touch via GitHub.
112 |
113 |
114 |
115 |
Why
116 |
We made this to show two things:
117 |
118 | Neural networks have become incredibly good at producing grammatically correct but completely nonsensical text
119 | There are so many nonsensical headlines nowadays, it's hard to distinguish fake from real
120 |
121 |
122 |
123 |
How
124 |
Content
125 |
126 | The fake headlines were generated by a neural network.
127 | We trained the network on 200'000 real headlines from the Huffington Post
128 | using OpenAI's GPT-2 .
129 |
130 |
131 | If you want to experiment yourself, you can find the dataset here .
132 |
133 |
Website
134 |
135 | Hosted on Github Pages using Cloudflare Workers & Key-Value store. Using native CSS.
136 |
137 |
138 |
142 |
143 |
License
144 | This project is released under the MIT License.
145 |
146 | Copyright (c) 2020 Tristan Menzinger
147 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
148 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
149 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0px;
4 | padding: 0px;
5 | width: 100vw;
6 | height: 100%;
7 | overflow: hidden;
8 | }
9 |
10 | .swipe-card {
11 | position: absolute;
12 |
13 | margin: auto;
14 | left: 0;
15 | right: 0;
16 |
17 | height: calc(100% - 4em);
18 | width: 80%;
19 | max-width: 400px;
20 |
21 | will-change: transform;
22 |
23 | cursor: pointer;
24 | }
25 |
26 | .swipe-card.smooth {
27 | transition: 0.5s ease-in-out;
28 | }
29 |
30 | .swipe-card.hide {
31 | display: none;
32 | }
33 |
34 | .swipe-card.smooth>.overlay {
35 | transition: 0.65s ease-in-out;
36 | will-change: transform;
37 | }
38 |
39 | .swipe-card.overlay {
40 | display: flex;
41 | justify-content: center;
42 |
43 | font-size: 50pt;
44 | font-weight: 600;
45 | color: white;
46 |
47 | opacity: 0;
48 |
49 | height: 100%;
50 | width: 100%;
51 | margin-top: -20px;
52 | }
53 |
54 | .swipe-card.overlay span {
55 | align-self: center;
56 | }
57 |
58 | .swipe-card.overlay.overlay-left {
59 | background-color: rgb(200, 0, 0);
60 | }
61 |
62 | .swipe-card.overlay.overlay-right {
63 | background-color: rgb(109, 168, 50);
64 | }
65 |
66 | body {
67 | display: flex;
68 | justify-content: center;
69 | }
70 |
71 | #container-wrapper {
72 | display: flex;
73 | flex-direction: column;
74 | align-self: center;
75 | overflow: hidden;
76 | height: 100%;
77 | width: 100vw;
78 |
79 | /*So the overflow: hidden can work;*/
80 | position: relative;
81 | }
82 |
83 | .rel-max-wrapper {
84 | position: relative;
85 | height: 100%;
86 | width: 100%;
87 | }
88 |
89 | /* Styling */
90 | .headline {
91 | flex-grow: 0;
92 | flex-shrink: 0;
93 | flex-basis: 40%;
94 | padding: 20px;
95 | overflow: none;
96 |
97 | -webkit-touch-callout: none;
98 | /* iOS Safari */
99 | -webkit-user-select: none;
100 | /* Safari */
101 | -khtml-user-select: none;
102 | /* Konqueror HTML */
103 | -moz-user-select: none;
104 | /* Old versions of Firefox */
105 | -ms-user-select: none;
106 | /* Internet Explorer/Edge */
107 | user-select: none;
108 | }
109 |
110 | .swipe-card .card-body {
111 | display: flex;
112 | flex-direction: column;
113 | padding: 0px;
114 | }
115 |
116 | .card-text {
117 | padding: 15px;
118 | max-height: 90%;
119 | overflow: hidden;
120 |
121 | font-size: 20pt;
122 | font-family: Helvetica, Roboto, Arial;
123 | font-weight: 700;
124 | }
125 |
126 | .card-info {
127 | display: flex;
128 | }
129 |
130 | .card-count {
131 | margin-left: auto;
132 | color: darkgray;
133 | float: right;
134 | }
135 |
136 | .card-difficulty {
137 | margin-left: 5px;
138 | }
139 |
140 | .card-difficulty {}
141 |
142 | #difficulty {
143 | position: absolute;
144 |
145 | width: 100%;
146 | height: 100%;
147 |
148 | display: none;
149 | /* flex */
150 | flex-direction: column;
151 |
152 | align-items: center;
153 | }
154 |
155 | #difficulty a {
156 | margin-bottom: 1.5rem;
157 | width: 100px;
158 | }
159 |
160 | #difficulty .btn-outline-secondary {
161 | border: none;
162 | }
163 |
164 | #info-done {
165 | position: absolute;
166 |
167 | width: 100%;
168 | height: 100%;
169 |
170 | display: none;
171 | /* flex */
172 | flex-direction: column;
173 |
174 | align-items: center;
175 | justify-content: center;
176 | }
177 |
178 | #info-done>span {
179 | display: flex;
180 | align-items: baseline;
181 | flex-direction: row;
182 | }
183 |
184 | #info-done>span>* {
185 | margin-right: 5px;
186 | }
187 | #container-headlines {
188 | max-height: 800px;
189 | }
190 |
191 | #container-title {
192 | align-self: center;
193 | padding: 3em;
194 | padding-top: 2em;
195 | padding-bottom: 2em;
196 |
197 | width: 100%;
198 | max-width: 500px;
199 |
200 | position: relative;
201 | }
202 |
203 | #container-title h1 {
204 | font-weight: 700;
205 | }
206 |
207 | #container-title>*:not(:first-child) {
208 | margin-top: -15px;
209 | }
210 |
211 | #container-title span.red,
212 | #question span.red {
213 | text-decoration: underline;
214 | text-decoration-color: rgb(200, 0, 0);
215 | }
216 |
217 | #container-title span.green,
218 | #question span.green {
219 | text-decoration: underline;
220 | text-decoration-color: rgb(109, 168, 50);
221 | }
222 |
223 | #container-title .instructions {
224 | font-size: 10pt;
225 | color: darkgray;
226 | }
227 |
228 | #difficulty #difficulty-picker {
229 | display: flex;
230 | flex-direction: column;
231 | /*margin-top: auto;*/
232 | /*margin-bottom: auto;*/
233 |
234 |
235 | justify-content: center;
236 | align-items: center;
237 |
238 | height: calc(100% - 3em - 10em);
239 | width: 80%;
240 | max-width: 400px;
241 | }
242 |
243 | #github,
244 | #about {
245 | position: absolute;
246 | text-decoration: underline;
247 | right: 3em;
248 | }
249 |
250 | #about {
251 | top: 3em;
252 | }
253 |
254 | #github {
255 | top: 3em;
256 | right: 6em;
257 | }
258 |
259 | #about>a,
260 | #github>a {
261 | font-size: 10pt;
262 | color: darkgray;
263 | }
264 |
265 | #info-done-results {
266 | display: flex;
267 | width: 100%;
268 | padding: 3em;
269 | flex-direction: column;
270 | }
271 |
272 | #info-done-results .info-card {
273 | width: 100%;
274 | margin-bottom: 0.5em;
275 | }
276 |
277 | .red {
278 | color: rgb(200, 0, 0);
279 | }
280 |
281 | .green {
282 | color: rgb(109, 168, 50);
283 | }
284 |
285 | .info-card i {
286 | position: absolute;
287 | right: 10px;
288 | top: 10px;
289 | color: darkgray;
290 | }
291 |
292 | .info-card .score {
293 | font-size: 10pt;
294 | }
295 |
296 | .info-card .title {
297 | font-weight: 700;
298 | }
299 |
300 | .last-headline {
301 | border: none;
302 | padding: 10px;
303 | transform: rotate(1deg);
304 | }
305 |
306 | .last-headline .card {
307 | padding: 8px;
308 | border-color: darkgray;
309 | height: 100%;
310 | }
311 |
312 | .last-headline>.card {
313 | background-color: white;
314 | background-image: url("data:image/svg+xml,%3Csvg width='6' height='6' viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23000000' fill-opacity='0.4' fill-rule='evenodd'%3E%3Cpath d='M5 0h1L0 6V5zM6 5v1H5z'/%3E%3C/g%3E%3C/svg%3E");
315 | }
316 |
317 | .confetti {
318 | position: absolute;
319 | height: 10px;
320 | width: 10px;
321 | z-index: 10000;
322 | will-change: transform;
323 | transition-timing-function: linear;
324 | }
325 |
326 | #celebration_container {
327 | position: absolute;
328 | width: 100%;
329 | height: 10px;
330 | }
331 |
332 | #container-streak {
333 | position: absolute;
334 | /*bottom: 15px;*/
335 | top: min(calc(100% - 25px), 965px);
336 | width: 100%;
337 | height: 10px;
338 | text-align: center;
339 | }
340 |
341 | .progressbar {
342 | display: inline-block;
343 | border-radius: 10px;
344 | border: 1px solid lightgray;
345 | height: 100%;
346 | width: 80%;
347 | max-width: 400px;
348 | }
349 |
350 | .progressbar .count {
351 | position: absolute;
352 | /*bottom: 7px;*/
353 | bottom: -4px;
354 | margin-left: -20px;
355 | color: darkgray;
356 | font-size: 10pt;
357 | text-align: left;
358 | text-align: right;
359 | }
360 |
361 | .progressbar .count.highlight {
362 | -webkit-animation: highlightkf 0.5s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
363 | animation: highlightkf 0.5s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
364 | }
365 |
366 | .progressbar .description {
367 | position: absolute;
368 | color: darkgray;
369 | font-size: 10pt;
370 | margin-top: -20px;
371 | }
372 |
373 | @-webkit-keyframes highlightkf {
374 |
375 | 0%,
376 | 100% {
377 | transform: scale(1, 1);
378 | }
379 |
380 | 50% {
381 | transform: scale(4, 4);
382 | }
383 |
384 | 100% {
385 | transform: scale(1, 1);
386 | }
387 | }
388 |
389 | .progressbar .progress {
390 | height: 100%;
391 | width: 0%;
392 | transition: 0.5s ease-in-out;
393 |
394 | background: rgb(0, 0, 0);
395 | background: linear-gradient(90deg, rgba(0, 0, 0, 1) 0%, rgba(255, 98, 0, 1) 100%);
396 | background-size: max(100%, 400px);
397 | }
398 |
399 |
400 | /*TEXT FLY-IN*/
401 | #flyin {
402 | position: absolute;
403 |
404 | top: 75%;
405 | left: calc(50% - min(50vw, 300px));
406 |
407 | height: 100px;
408 | width: 100vw;
409 | max-width: 600px;
410 |
411 | text-align: center;
412 |
413 | transform: rotate(0deg);
414 | transition: transform 0s linear;
415 | }
416 |
417 | #flyin.fly {
418 | z-index: 1000;
419 | }
420 |
421 | #flyin > #flyin-text {
422 | position: absolute;
423 |
424 | text-align: center;
425 |
426 | left: 0;
427 | top: 0;
428 | width: 100%;
429 | color: darkgray;
430 | font-size: 25pt;
431 | font-weight: 600;
432 | opacity: 0;
433 | }
434 |
435 | #flyin.fly #flyin-text {
436 | animation: fly-in-animation 1s linear;
437 | }
438 |
439 | @-webkit-keyframes fly-in-animation {
440 | 0% {
441 | opacity: 0;
442 | transform: scale(1.3);
443 | }
444 | 20% {
445 | opacity: 1;
446 | transform: scale(1.3);
447 | }
448 |
449 | 80% {
450 | opacity: 1;
451 | }
452 |
453 | 100% {
454 | transform: scale(0.75);
455 | opacity: 0;
456 | }
457 | }
458 |
459 |
460 | /*ANIMATIONS */
461 |
462 | .shake-bottom1 {
463 | -webkit-animation: shake-bottom1 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
464 | animation: shake-bottom1 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
465 | }
466 |
467 | .shake-bottom2 {
468 | -webkit-animation: shake-bottom2 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
469 | animation: shake-bottom2 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
470 | }
471 |
472 | .shake-bottom3 {
473 | -webkit-animation: shake-bottom3 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
474 | animation: shake-bottom3 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
475 | }
476 |
477 | /* ----------------------------------------------
478 | * Generated by Animista on 2020-6-9 20:30:46
479 | * Licensed under FreeBSD License.
480 | * See http://animista.net/license for more info.
481 | * w: http://animista.net, t: @cssanimista
482 | * ---------------------------------------------- */
483 |
484 | /**
485 | * ----------------------------------------
486 | * animation shake-bottom
487 | * ----------------------------------------
488 | */
489 | @-webkit-keyframes shake-bottom1 {
490 |
491 | 0%,
492 | 100% {
493 | -webkit-transform: rotate(0deg);
494 | transform: rotate(0deg);
495 | -webkit-transform-origin: 50% 100%;
496 | transform-origin: 50% 100%;
497 | }
498 |
499 | 10% {
500 | -webkit-transform: rotate(0.125deg);
501 | transform: rotate(0.125deg);
502 | }
503 |
504 | 20%,
505 | 40%,
506 | 60% {
507 | -webkit-transform: rotate(-0.25deg);
508 | transform: rotate(-0.25deg);
509 | }
510 |
511 | 30%,
512 | 50%,
513 | 70% {
514 | -webkit-transform: rotate(0.25deg);
515 | transform: rotate(0.25deg);
516 | }
517 |
518 | 80% {
519 | -webkit-transform: rotate(-0.125deg);
520 | transform: rotate(-0.125deg);
521 | }
522 |
523 | 90% {
524 | -webkit-transform: rotate(0.125deg);
525 | transform: rotate(0.125deg);
526 | }
527 | }
528 |
529 | @-webkit-keyframes shake-bottom2 {
530 |
531 | 0%,
532 | 100% {
533 | -webkit-transform: rotate(0deg);
534 | transform: rotate(0deg);
535 | -webkit-transform-origin: 50% 100%;
536 | transform-origin: 50% 100%;
537 | }
538 |
539 | 10% {
540 | -webkit-transform: rotate(0.25deg);
541 | transform: rotate(0.25deg);
542 | }
543 |
544 | 20%,
545 | 40%,
546 | 60% {
547 | -webkit-transform: rotate(-0.5deg);
548 | transform: rotate(-0.5deg);
549 | }
550 |
551 | 30%,
552 | 50%,
553 | 70% {
554 | -webkit-transform: rotate(0.25deg);
555 | transform: rotate(0.25deg);
556 | }
557 |
558 | 80% {
559 | -webkit-transform: rotate(-0.5deg);
560 | transform: rotate(-0.5deg);
561 | }
562 |
563 | 90% {
564 | -webkit-transform: rotate(0.25deg);
565 | transform: rotate(0.25deg);
566 | }
567 | }
568 |
569 | @-webkit-keyframes shake-bottom3 {
570 |
571 | 0%,
572 | 100% {
573 | -webkit-transform: rotate(0deg) scale(1.0);
574 | transform: rotate(0deg) scale(1.0);
575 | -webkit-transform-origin: 50% 100%;
576 | transform-origin: 50% 100%;
577 | }
578 |
579 | 10% {
580 | -webkit-transform: rotate(0.3deg) scale(1.05);
581 | transform: rotate(0.3deg) scale(1.05);
582 | }
583 |
584 | 20%,
585 | 40%,
586 | 60% {
587 | -webkit-transform: rotate(-0.7deg) scale(1.1);
588 | transform: rotate(-0.7deg) scale(1.1);
589 | }
590 |
591 | 30%,
592 | 50%,
593 | 70% {
594 | -webkit-transform: rotate(0.3deg) scale(1.05);
595 | transform: rotate(0.3deg) scale(1.05);
596 | }
597 |
598 | 80% {
599 | -webkit-transform: rotate(-0.7deg) scale(1.1);
600 | transform: rotate(-0.7deg) scale(1.1);
601 | }
602 |
603 | 90% {
604 | -webkit-transform: rotate(0.3deg) scale(1.05);
605 | transform: rotate(0.3deg) scale(1.05);
606 | }
607 | }
608 |
609 | .bounce-right {
610 | -webkit-animation: bounce-right 0.8s both;
611 | animation: bounce-right 0.8s both;
612 | }
613 |
614 | /* ----------------------------------------------
615 | * Generated by Animista on 2020-6-9 20:34:13
616 | * Licensed under FreeBSD License.
617 | * See http://animista.net/license for more info.
618 | * w: http://animista.net, t: @cssanimista
619 | * ---------------------------------------------- */
620 |
621 | /**
622 | * ----------------------------------------
623 | * animation bounce-right
624 | * ----------------------------------------
625 | */
626 | @-webkit-keyframes bounce-right {
627 | 0% {
628 | -webkit-transform: translateX(48px) scale(1.2);
629 | transform: translateX(48px) scale(1.2);
630 | -webkit-animation-timing-function: ease-in;
631 | animation-timing-function: ease-in;
632 | opacity: 1;
633 | }
634 |
635 | 24% {
636 | opacity: 1;
637 | }
638 |
639 | 40% {
640 | -webkit-transform: translateX(26px);
641 | transform: translateX(26px);
642 | -webkit-animation-timing-function: ease-in;
643 | animation-timing-function: ease-in;
644 | }
645 |
646 | 65% {
647 | -webkit-transform: translateX(13px);
648 | transform: translateX(13px);
649 | -webkit-animation-timing-function: ease-in;
650 | animation-timing-function: ease-in;
651 | }
652 |
653 | 82% {
654 | -webkit-transform: translateX(6.5px);
655 | transform: translateX(6.5px);
656 | -webkit-animation-timing-function: ease-in;
657 | animation-timing-function: ease-in;
658 | }
659 |
660 | 93% {
661 | -webkit-transform: translateX(4px);
662 | transform: translateX(4px);
663 | -webkit-animation-timing-function: ease-in;
664 | animation-timing-function: ease-in;
665 | }
666 |
667 | 25%,
668 | 55%,
669 | 75%,
670 | 87%,
671 | 98% {
672 | -webkit-transform: translateX(0px);
673 | transform: translateX(0px);
674 | -webkit-animation-timing-function: ease-out;
675 | animation-timing-function: ease-out;
676 | }
677 |
678 | 100% {
679 | -webkit-transform: translateX(0px) scale(1.0);
680 | transform: translateX(0px) scale(1.0);
681 | -webkit-animation-timing-function: ease-out;
682 | animation-timing-function: ease-out;
683 | opacity: 1;
684 | }
685 | }
686 |
687 | /*FIRE*/
688 |
689 | #container-streak.max-1 .mo-fire {
690 | width: 30px;
691 | height: 30px;
692 | margin-top: -45px;
693 | margin-left: calc(50vw + min(40%, 200px) - 20px);
694 | }
695 |
696 | #container-streak.max-2 .mo-fire {
697 | width: 45px;
698 | height: 45px;
699 | margin-top: -67px;
700 | margin-left: calc(50vw + min(40%, 200px) - 27px);
701 | }
702 |
703 | #container-streak.max-3 .mo-fire {
704 | width: 60px;
705 | height: 60px;
706 | margin-top: -90px;
707 | margin-left: calc(50vw + min(40%, 200px) - 40px);
708 | }
709 |
710 | #container-streak.max-4 .mo-fire {
711 | width: 80px;
712 | height: 80px;
713 | margin-top: -120px;
714 | margin-left: calc(50vw + min(40%, 200px) - 55px);
715 | }
716 |
717 | #container-streak.max .mo-fire {
718 | opacity: 1;
719 | transition: 0.1s ease-in !important;
720 | }
721 |
722 | .mo-fire {
723 | align-items: baseline;
724 | text-align: center;
725 |
726 | transition: width 1s ease-in, height 1s ease-in, opacity 0.2s ease-in;
727 | opacity: 0;
728 | margin-left: calc(50vw + min(40%, 200px) - 5px);
729 |
730 | margin-top: 0px;
731 | height: 0px;
732 | width: 0px;
733 | left: 50%;
734 | }
735 |
736 | .mo-fire svg {
737 | width: 100%;
738 | height: auto;
739 | position: relative
740 | }
741 |
742 | .flame {
743 | animation-name: flamefly;
744 | animation-duration: 2s;
745 | animation-timing-function: linear;
746 | animation-iteration-count: infinite;
747 | opacity: 0;
748 | transform-origin: 50% 50% 0;
749 | }
750 |
751 | .flame.one {
752 | animation-delay: 1s;
753 | animation-duration: 3s;
754 | }
755 |
756 | .flame3.two {
757 | animation-duration: 5s;
758 | animation-delay: 1s;
759 | }
760 |
761 | .flame-main {
762 | animation-name: flameWobble;
763 | animation-duration: 3s;
764 | animation-timing-function: linear;
765 | animation-iteration-count: infinite;
766 | }
767 |
768 | .flame-main.one {
769 | animation-duration: 4s;
770 | animation-delay: 1s;
771 | }
772 |
773 | .flame-main.two {
774 | animation-duration: 3s;
775 | animation-delay: 2s;
776 | }
777 |
778 | .flame-main.three {
779 | animation-duration: 2.1s;
780 | animation-delay: 3s;
781 | }
782 |
783 | .flame-main.four {
784 | animation-duration: 3.2s;
785 | animation-delay: 4s;
786 | }
787 |
788 | .flame-main.five {
789 | animation-duration: 2.5s;
790 | animation-delay: 5s;
791 | }
792 |
793 | @keyframes flameWobble {
794 | 50% {
795 | transform: scale(1, 1.2) translate(0, -30px) rotate(-2deg);
796 | }
797 | }
798 |
799 | @keyframes flamefly {
800 | 0% {
801 | transform: translate(0) rotate(180deg);
802 | }
803 |
804 | 50% {
805 | opacity: 1;
806 | }
807 |
808 | 100% {
809 | transform: translate(-20px, -100px) rotate(180deg);
810 | opacity: 0;
811 | }
812 | }
813 |
814 | /*Seriously small screen handling */
815 | @media only screen and (max-height: 700px) {
816 | .card-text {
817 | font-size: 15pt;
818 | }
819 |
820 | #container-title .instructions {
821 | font-size: 8pt;
822 | }
823 |
824 | #container-title {
825 | padding: 2em;
826 | }
827 | #container-title h4 {
828 | font-size: 1.2rem;
829 | }
830 | #container-title h1 {
831 | font-size: 2rem;
832 | }
833 |
834 | #github a, #about a {
835 | font-size: 8pt;
836 | }
837 | #about {
838 | right: 2em;
839 | }
840 | #github {
841 | right: 4.5em;
842 | }
843 |
844 | .progressbar .description {
845 | font-size: 8pt;
846 | }
847 | }
848 |
849 |
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Is This Headline Fake or Not?
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
Is this Headline
29 | fake or not ?
30 |
31 |
45 |
46 |
47 |
All done.
48 |
49 | You got
50 | 3 / 10
51 | right.
52 |
53 |
54 |
55 | or
56 |
57 |
58 |
59 |
73 |
85 |
86 |
87 |
88 |
89 |
Is this Headline
90 |
fake or not ?
91 |
92 | We live in crazy times - but can you tell how crazy?
93 |
94 | Swipe right if you think it's real, left if fake.
95 |
96 |
97 |
98 |
99 |
107 |
108 |
109 |
110 |
Streak
111 |
112 |
113 |
114 |
115 |
118 |
120 |
122 |
124 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | let DEV = false;
2 |
3 | const FALSE_POSITIVE = 100;
4 | const FALSE_NEGATIVE = 200;
5 |
6 | const FALSE_NEGATIVE_SENTENCES = [
7 | "That one was fake",
8 | "That didn't happen",
9 | "Nope, that was fake",
10 | "That didn't happen",
11 | "Could've happened"
12 | ];
13 |
14 | const FALSE_POSITIVE_SENTENCES = [
15 | "That really happend",
16 | "Yea, that was real",
17 | "Nope, that was real",
18 | "That one was real",
19 | "Uhh, that actually happened"
20 | ];
21 |
22 |
23 | class Card {
24 | constructor(headline_json, count, settings) {
25 | this.title = headline_json.text;
26 | this.is_real = headline_json.is_real;
27 | this.id = headline_json.id;
28 |
29 | this.count = count;
30 |
31 | this._create_div();
32 |
33 | this.overlay_left = this.div.querySelector(".overlay-left");
34 | this.overlay_right = this.div.querySelector(".overlay-right");
35 |
36 | settings = settings ? settings : {};
37 | this.threshold_go = settings["threshold_go"] ? settings["threshold_go"] : 0.4;
38 | this.overlay_multiplier = settings["overlay_multiplier"] ? settings["overlay_multiplier"] : 2;
39 | this.fade_multiplier = settings["fade_multiplier"] ? settings["fade_multiplier"] : 0.5;
40 |
41 | this.initial_rotation = (Math.random() - 0.5) * 5;
42 | this.initial_x_offset = (Math.random() - 0.5) * 5;
43 | this.initial_y_offset = (Math.random() - 0.5) * 5;
44 |
45 | // Hide out of view by default
46 | this.div.style.transform = `translateX(${screen.width+Math.random()*200}px) translateY(${(Math.random()-0.5)*screen.height/3}px) translateZ(1000px) rotate(${(Math.random()-0.5)*20}deg) rotateX(40deg) rotateY(30deg)`;
47 |
48 | this.gone = false;;
49 |
50 | }
51 |
52 | _create_div() {
53 | let template = `
54 |
55 |
Fake
56 |
Real
57 |
58 |
59 |
${this.title}
60 |
61 |
`;
62 | this.div = div_from_template(template);
63 | }
64 |
65 | show() {
66 | this.div.classList.add("smooth");
67 | this.div.style.transform = `translateX(${this.initial_x_offset}px) translateY(${this.initial_y_offset}px) rotate(${this.initial_rotation}deg)`;
68 | }
69 |
70 | activate() {
71 |
72 | this.div.ontouchstart = (event) => {
73 | this.div.classList.remove("smooth");
74 | this.start_x = event.touches[0].clientX;
75 | this.start_y = event.touches[0].clientY;
76 | this.width = this.div.getBoundingClientRect().width;
77 | }
78 | this.div.ontouchmove = (event) => {
79 | const percentage_progress = (event.touches[0].clientX - this.start_x) / this.width;
80 | this.set_progress(percentage_progress);
81 | }
82 | this.div.ontouchend = (event) => {
83 | const percentage_progress = (event.changedTouches[0].clientX - this.start_x) / this.width;
84 | if (Math.abs(percentage_progress) > this.threshold_go) {
85 | this.go(percentage_progress / Math.abs(percentage_progress));
86 | } else {
87 | this.comeback();
88 | }
89 | }
90 |
91 | let drag = false;
92 | this.div.onmousedown = (event) => {
93 | drag = true;
94 | this.div.classList.remove("smooth");
95 | this.start_x = event.clientX;
96 | this.start_y = event.clientY;
97 | this.width = this.div.getBoundingClientRect().width;
98 | }
99 | this.div.onmousemove = (event) => {
100 | if (drag) {
101 | const percentage_progress = (event.clientX - this.start_x) / this.width;
102 | this.set_progress(percentage_progress);
103 | }
104 | }
105 | this.div.onmouseup = (event) => {
106 | drag = false;
107 |
108 | const percentage_progress = (event.clientX - this.start_x) / this.width;
109 | if (Math.abs(percentage_progress) > this.threshold_go) {
110 | this.go(percentage_progress / Math.abs(percentage_progress));
111 | } else {
112 | this.comeback();
113 | }
114 | }
115 | }
116 |
117 | deactivate() {
118 | this.div.ontouchstart = () => {}
119 | this.div.ontouchmove = () => {}
120 | this.div.ontouchend = () => {}
121 | }
122 |
123 | set_progress(percentage_progress) {
124 | if (!this.gone) {
125 | const x_transform = this.initial_x_offset + percentage_progress * this.width;
126 | const rotation = this.initial_rotation + 10 * percentage_progress;
127 |
128 | this.div.style.opacity = 1 - sigmoid((Math.abs(this.fade_multiplier * percentage_progress) - 0.75) * 10);
129 | this.div.style.transform = `translateX(${x_transform}px) translateY(${this.initial_y_offset}px) rotate(${rotation}deg)`;
130 |
131 | const opacity = sigmoid((Math.abs(this.overlay_multiplier * percentage_progress) - 0.5) * 5);
132 | // console.log(opacity);
133 | if (percentage_progress < 0) {
134 | this.overlay_left.style.opacity = opacity;
135 | } else {
136 | this.overlay_right.style.opacity = opacity;
137 | }
138 | }
139 | }
140 |
141 | comeback() {
142 | this.div.classList.add("smooth");
143 |
144 | this.overlay_left.style.opacity = 0;
145 | this.overlay_right.style.opacity = 0;
146 |
147 | this.div.style.opacity = 1;
148 | this.div.style.transform = `translateX(${this.initial_x_offset}px) translateY(${this.initial_y_offset}px) rotate(${this.initial_rotation}deg)`;
149 | }
150 |
151 | go(direction) {
152 | if (!this.gone) {
153 | this.div.classList.add("smooth");
154 | this.set_progress(direction * 3);
155 | setTimeout(() => {
156 | this.div.classList.add("hide");
157 | }, 1000);
158 | if (this.stack) {
159 | this.stack.next();
160 | }
161 |
162 | this.gone = true;
163 |
164 | if (direction < 0)
165 | this.left();
166 | else
167 | this.right();
168 | }
169 | }
170 |
171 | // Opinion Real
172 | left() {
173 | if(this.is_real) {
174 | delete_progress(FALSE_POSITIVE);
175 |
176 | submit_answer(this.id, false);
177 | } else {
178 | add_progress();
179 | submit_answer(this.id, true);
180 | }
181 | }
182 |
183 | // Opinion Fake
184 | right() {
185 | if(!this.is_real) {
186 | delete_progress(FALSE_NEGATIVE);
187 |
188 | submit_answer(this.id, false);
189 | } else {
190 | add_progress();
191 | submit_answer(this.id, true);
192 | }
193 | }
194 | }
195 |
196 | function submit_answer(id, was_correct) {
197 | if(!DEV) {
198 | return fetch("https://fakeornot.menzinger.workers.dev", {
199 | method: "post",
200 | body: JSON.stringify({
201 | "id": id,
202 | "correct": was_correct
203 | })
204 | });
205 | }else {
206 | console.log("process not submitted - dev mode")
207 | }
208 | }
209 |
210 | function add_progress(percent_to_add = 10) {
211 | let progress = document.querySelector(".progress");
212 | let count = document.querySelector(".count");
213 | let progressbar = document.querySelector(".progressbar");
214 | let container = document.querySelector("#container-streak");
215 |
216 | if (progress.percent == null)
217 | progress.percent = 0;
218 |
219 | old_progress = progress.percent
220 | new_progress = progress.percent + percent_to_add;
221 | progress.percent = new_progress;
222 |
223 | // console.log(old_progress, new_progress)
224 |
225 | if (old_progress < 90 && new_progress >= 90)
226 | animate(container, "shake-bottom3");
227 |
228 | if (old_progress < 80 && new_progress >= 80)
229 | animate(container, "shake-bottom2");
230 |
231 | if (old_progress < 70 && new_progress >= 70)
232 | animate(container, "shake-bottom1");
233 |
234 | if (old_progress < 110 && new_progress >= 110) {
235 | container.classList.add("max", "max-1");
236 | animate(container, "shake-bottom1");
237 | } else if (old_progress < 150 && new_progress >= 150) {
238 | container.classList.add("max", "max-2");
239 | animate(container, "shake-bottom2");
240 | } else if (old_progress < 200 && new_progress >= 200) {
241 | container.classList.add("max", "max-3");
242 | animate(container, "shake-bottom3");
243 | } else if (old_progress < 250 && new_progress >= 250) {
244 | container.classList.add("max", "max-4");
245 | animate(container, "shake-bottom3");
246 | } else if (new_progress > 100) {
247 | animate(container, "shake-bottom1");
248 | }
249 |
250 | progress.style.width = (progress.percent >= 100 ? 100 : progress.percent) + "%";
251 |
252 | count.textContent = new_progress / percent_to_add;
253 | animate(count, "highlight");
254 |
255 | }
256 |
257 | function animate(element, animation_class, time = 500) {
258 | element.classList.add(animation_class)
259 | setTimeout(() => {
260 | element.classList.remove(animation_class)
261 | }, time);
262 | }
263 |
264 | function delete_progress(type) {
265 |
266 |
267 | if(type) {
268 | let text;
269 |
270 | if(type == FALSE_NEGATIVE)
271 | text = FALSE_NEGATIVE_SENTENCES[Math.floor(Math.random()*FALSE_NEGATIVE_SENTENCES.length)];
272 | else
273 | text = FALSE_POSITIVE_SENTENCES[Math.floor(Math.random()*FALSE_POSITIVE_SENTENCES.length)];
274 |
275 | let flyin = document.getElementById("flyin");
276 | let flyin_text = flyin.querySelector("#flyin-text");
277 | flyin_text.textContent = text;
278 |
279 | flyin.style.transform = `rotate(${(Math.random()-0.5)*30}deg)`;
280 |
281 | animate(flyin, "fly", 1000);
282 | }
283 |
284 | let progress = document.querySelector(".progress");
285 | let progressbar = document.querySelector(".progressbar");
286 | let container = document.querySelector("#container-streak");
287 | let count = document.querySelector(".count");
288 |
289 | container.classList.remove("max");
290 | container.classList.remove("max-1");
291 | container.classList.remove("max-2");
292 | container.classList.remove("max-3");
293 | container.classList.remove("max-4");
294 |
295 | animate(progressbar, "bounce-right");
296 |
297 | progress.percent = 0;
298 | progress.style.width = progress.percent + "%";
299 |
300 | count.textContent = "";
301 | }
302 |
303 | async function confetti_rain(color = "red", amount = 150) {
304 | let celebration_container = document.getElementById("celebration_container");
305 | let confetti = [];
306 | for (let x = 0; x < amount; x++) {
307 | let c = document.createElement("div")
308 | c.classList.add("confetti")
309 |
310 | c.style.opacity = 0.8;
311 |
312 | let height = 5 + 20 * Math.random()
313 |
314 | c.style.height = `${5+5*Math.random()}px`;
315 | c.style.width = `${50 / height}px`;
316 | // c.style.backgroundColor = `rgb(${255*Math.random()}, ${255*Math.random()}, ${255*Math.random()})`;
317 | c.style.backgroundColor = color;
318 | c.style.top = -10 + "px";
319 | c.style.left = 10 + screen.width * Math.random() * 0.92 + "px";
320 |
321 | let drop = (1 + Math.random() * 2) / 1.5;
322 | let start = 2 * Math.random();
323 | let offset = 0.75;
324 | c.style.transition = `all ${drop}s linear ${start}s, opacity linear ${drop-offset}s ${start}s`;
325 |
326 | celebration_container.appendChild(c)
327 | confetti.push(c);
328 | }
329 |
330 | for (let c of confetti) {
331 | setTimeout(() => {
332 | c.style.transform = `translateY(${screen.height/4 + Math.random() * screen.height}px) rotate(${(Math.random()-0.5)*180}deg)`;
333 | c.style.opacity = 0;
334 | }, 10);
335 | }
336 |
337 | setTimeout(() => {
338 | console.log(confetti.length)
339 | for (let c of confetti) {
340 | c.remove();
341 | }
342 | }, 3000);
343 | }
344 |
345 | class Stack {
346 | constructor(cards, empty_callback) {
347 | this.cards = cards;
348 | for (let card of cards) {
349 | card.stack = this;
350 | }
351 |
352 | this.empty_callback = empty_callback;
353 |
354 | this.index = this.cards.length - 1;
355 | this.current = this.cards[this.index];
356 | }
357 |
358 | add_to_container() {
359 | let container = document.querySelector("#container-headlines");
360 | for (let card of this.cards) {
361 | container.appendChild(card.div);
362 | }
363 | }
364 |
365 | async show_all() {
366 | for (let card of this.cards) {
367 | await sleep(75 + Math.random() * 50);
368 | card.show()
369 | }
370 | this.current.activate();
371 | }
372 |
373 | next() {
374 | this.index = this.index - 1;
375 | if (this.index >= 0) {
376 | this.current = this.cards[this.index];
377 | this.current.activate();
378 | } else {
379 | this.empty_callback();
380 | }
381 | }
382 | }
383 |
384 | let div_from_template = (filled_template_string) => {
385 | let wrapper = document.createElement("div");
386 | wrapper.innerHTML = filled_template_string;
387 | return wrapper.firstElementChild;
388 | }
389 |
390 | function sigmoid(t) {
391 | return 1 / (1 + Math.exp(-t));
392 | }
393 |
394 | function sleep(ms) {
395 | return new Promise(resolve => setTimeout(resolve, ms));
396 | }
397 |
398 |
399 | function headlines_to_cards(headlines) {
400 | let cards = []
401 | for (let i = 0; i < 10; i++) {
402 | cards.push(new Card(headlines[i], headlines.length - i));
403 | }
404 | return cards
405 | }
406 |
407 | function get_new_headlines() {
408 | return fetch("https://get-headlines.fake-or-not.workers.dev/").then(response => response.json());
409 | }
410 |
411 | async function play(empty_callback = play) {
412 | let cards = headlines_to_cards(await get_new_headlines());
413 | let stack = new Stack(cards, empty_callback = empty_callback);
414 | stack.add_to_container();
415 | stack.show_all();
416 | }
417 |
418 | async function init() {
419 | const queryParams = new URLSearchParams(window.location.search);
420 | const difficulty = queryParams.get('difficulty');
421 |
422 | play()
423 | }
424 |
--------------------------------------------------------------------------------