├── favicon.png ├── audio ├── bonk.mp3 ├── boom.mp3 ├── pop.mp3 ├── chimes.mp3 ├── party.mp3 ├── pencil.mp3 ├── pluck0.mp3 ├── pluck1.mp3 ├── pluck2.mp3 ├── pluck3.mp3 ├── snip0.mp3 ├── snip1.mp3 ├── snip2.mp3 ├── trash.mp3 ├── bg_music.mp3 ├── button0.mp3 ├── button1.mp3 ├── button2.mp3 ├── contagion.mp3 ├── squeak_up.mp3 ├── party_short.mp3 ├── scratch_in.mp3 ├── scratch_out.mp3 ├── squeak_down.mp3 └── pencil_short.mp3 ├── social └── thumb.png ├── sprites ├── line.png ├── nasa.png ├── peeps.png ├── pencil.png ├── scratch.png ├── bonus │ ├── ee.png │ ├── map.png │ ├── trust.png │ ├── polygons.png │ ├── connected.png │ ├── connection1.png │ ├── connection2.png │ ├── contagion1.png │ ├── contagion2.png │ ├── contagion3.png │ ├── contagion4.png │ └── surowieki.jpg ├── confetti.png ├── icons │ ├── red.png │ ├── blue.png │ ├── gray.png │ └── yellow.png ├── ui │ ├── arrow.png │ ├── bonus.png │ ├── sound.png │ └── sharing.png ├── button_large.png ├── red_button.png ├── small_world.png ├── sandbox_tools.png ├── tutorial_connect.png └── tutorial_disconnect.png ├── supporters ├── peeps │ ├── ljt.png │ ├── nick.png │ ├── noel.png │ ├── andy_ellis.png │ ├── ben_mathes.png │ ├── joe_sevits.png │ ├── sean_riley.png │ ├── yuhan_kuo.png │ ├── zach_smith.png │ ├── aimee_jarboe.png │ ├── chad_sansing.png │ ├── dylan_field.png │ ├── kate_fractal.png │ ├── matt_hughes.png │ ├── michael_duke.png │ ├── michael_huff.png │ ├── natalie_sun.png │ ├── rafael_ffont.png │ ├── travis_ross.png │ ├── andrew_grondin.png │ ├── david_e_weekly.png │ ├── jared_cosulich.png │ ├── phil_dougherty.png │ ├── srini_kadamati.png │ └── christopher_rodier.png └── polygons │ ├── c.png │ ├── m.png │ ├── aaron.png │ ├── brian.png │ ├── green.png │ ├── jack.png │ ├── laura.png │ ├── ljt.png │ ├── mga.png │ ├── mikey.png │ ├── nick.png │ ├── noel.png │ ├── sean.png │ ├── alex_g.png │ ├── dave_tu.png │ ├── dominc.png │ ├── grvling.png │ ├── jaakko.png │ ├── kailys.png │ ├── macdiva.png │ ├── maciej.png │ ├── nikita.png │ ├── quartz.png │ ├── s_smith.png │ ├── sal_go.png │ ├── alex_mole.png │ ├── amy_fuchs.png │ ├── andy_ellis.png │ ├── aran_jger.png │ ├── ben_kraft.png │ ├── ben_mathes.png │ ├── bob_wise.png │ ├── boondoggle.png │ ├── cathy_deng.png │ ├── ceceron44.png │ ├── cyrus_levy.png │ ├── evan_rocha.png │ ├── gui_ambros.png │ ├── joe_sevits.png │ ├── josh_leong.png │ ├── lexszero.png │ ├── mary_bush.png │ ├── nat_alison.png │ ├── raspbeguy.png │ ├── rob_napier.png │ ├── rohit_bhat.png │ ├── sam_dorios.png │ ├── sam_remis.png │ ├── sean_riley.png │ ├── settworks.png │ ├── tom_lieber.png │ ├── upidaisy.png │ ├── yuhan_kuo.png │ ├── zach_smith.png │ ├── adam_zeiner.png │ ├── aiden_clack.png │ ├── aimee_jarboe.png │ ├── alejo_amiras.png │ ├── alex_dytrych.png │ ├── amy_traylor.png │ ├── aria_minaei.png │ ├── brian_lange.png │ ├── cedric_rossi.png │ ├── chad_sansing.png │ ├── chris_makler.png │ ├── colin_liotta.png │ ├── cristy_stone.png │ ├── curtis_frye.png │ ├── da_liberman.png │ ├── dave_mcclure.png │ ├── dylan_field.png │ ├── eli_jeschke.png │ ├── evan_shulman.png │ ├── fred_ehrsam.png │ ├── fred_tschepp.png │ ├── glen_e_ivey.png │ ├── greg_nelson.png │ ├── hilary_fried.png │ ├── idahosa_ness.png │ ├── istvn_hamar.png │ ├── ivo_murrell.png │ ├── jacob_feala.png │ ├── jasmine_ren.png │ ├── jessica_osio.png │ ├── joe_shumaker.png │ ├── jonathan_ng.png │ ├── josh_comeau.png │ ├── josh_koenig.png │ ├── julie_franke.png │ ├── karen_cooper.png │ ├── kate_fractal.png │ ├── leopard_dan.png │ ├── linda_liukas.png │ ├── lucas_garron.png │ ├── matt_hughes.png │ ├── michael_duke.png │ ├── michael_huff.png │ ├── natalie_sun.png │ ├── nimrod_kimhi.png │ ├── pablo_molins.png │ ├── paul_daoust.png │ ├── paul_sztajer.png │ ├── peter_kadlot.png │ ├── rae_mcintosh.png │ ├── rafael_ffont.png │ ├── robert_aran.png │ ├── rupert_moore.png │ ├── sam_prinssen.png │ ├── shreeya_goel.png │ ├── steve_krouse.png │ ├── steve_ryman.png │ ├── tal_rotbart.png │ ├── tamir_bahar.png │ ├── todd_siegel.png │ ├── toph_tucker.png │ ├── travis_ross.png │ ├── yinhung_hsu.png │ ├── abhishek_modi.png │ ├── aditya_bhargava.png │ ├── aiman_josefsson.png │ ├── andrew_grondin.png │ ├── anshul_dhawan.png │ ├── artwalks_europe.png │ ├── bohdan_makohin.png │ ├── brianna_bergen.png │ ├── bruce_steinberg.png │ ├── caelyn_mcaulay.png │ ├── charlie_stigler.png │ ├── chris_hallacy.png │ ├── clive_freeman.png │ ├── colin_anderson.png │ ├── david_e_weekly.png │ ├── david_sallmann.png │ ├── elmar_schlueter.png │ ├── eric_chisholm.png │ ├── fiona_nielsen.png │ ├── freddie_firth.png │ ├── fritz_solares.png │ ├── harry_brisson.png │ ├── igor_krawczuk.png │ ├── industrialrobot.png │ ├── jacopo_cascioli.png │ ├── jamieson_taylor.png │ ├── jared_cosulich.png │ ├── jason_crawford.png │ ├── jeaneudes_denis.png │ ├── jesper_the_end.png │ ├── josef_komenda.png │ ├── joshua_horowitz.png │ ├── kaitlin_smith.png │ ├── kendra_lockman.png │ ├── kevin_zollman.png │ ├── kumara_uttara.png │ ├── laura_baldwin.png │ ├── leslie_robinson.png │ ├── lukas_wegmann.png │ ├── marconi_pereira.png │ ├── matthew_weber.png │ ├── maxim_sidorov.png │ ├── michael_donatz.png │ ├── michael_handler.png │ ├── mikkel_snyder.png │ ├── molly_mcfadden.png │ ├── naomi_alderman.png │ ├── nelson_crespo.png │ ├── nick_gallegos.png │ ├── noah_richards.png │ ├── patrick_bobell.png │ ├── phil_dougherty.png │ ├── postmillenial.png │ ├── raymond_keller.png │ ├── rebecca_wigandt.png │ ├── rob_mckaughan.png │ ├── robert_duncan.png │ ├── rory_sutherland.png │ ├── sara_hekimian.png │ ├── scott_donaldson.png │ ├── serena_casanova.png │ ├── sergiy_protsiv.png │ ├── srini_kadamati.png │ ├── steve_waldman.png │ ├── teodor_zhechev.png │ ├── toby_schachman.png │ ├── trevor_haldenby.png │ ├── tudor_iliescu.png │ ├── william_ohanley.png │ ├── wouter_slegers.png │ ├── yates_buckley.png │ ├── yury_melnichek.png │ ├── zan_armstrong.png │ ├── alexander_zacherl.png │ ├── alexandre_barret.png │ ├── andrea_di_biagio.png │ ├── animation_at_work.png │ ├── anthony_pecorella.png │ ├── benjamin_lindsay.png │ ├── christopher_goes.png │ ├── dag_frode_solberg.png │ ├── iain_kirkpatrick.png │ ├── jan_van_nigtevegt.png │ ├── kelvin_nishikawa.png │ ├── matthew_campbell.png │ ├── michael_merchant.png │ ├── natalie_rothfels.png │ ├── patrick_henderson.png │ ├── reed_copperstrand.png │ ├── shakir_alshareef.png │ ├── silviu_strliciuc.png │ ├── thomas_ballinger.png │ ├── william_b_everett.png │ ├── christopher_ferrie.png │ ├── christopher_rodier.png │ ├── dinos_papadopoulos.png │ ├── florencia_herra_vega.png │ ├── jacob_james_leaney.png │ ├── josh_cheeseness_bush.png │ ├── juan_ignacio_terraza.png │ ├── mikayla_hutchinson.png │ ├── nishanth_sudharsanam.png │ ├── stefano_baccianella.png │ ├── allison_cliftjennings.png │ ├── gabriel_barbosa_nunes.png │ ├── iago_medeiros_cordeiro.png │ ├── caio_vinicius_do_nascimento.png │ └── jacob_christian_munchandersen.png ├── css ├── PatrickHand-Regular.ttf └── index.css ├── js ├── chapters │ ├── I_Credits.js │ ├── J_Sandbox.js │ ├── B_Introduction.js │ ├── H_Conclusion.js │ ├── A_Preloader.js │ ├── G_Small_World.js │ ├── F_Bonding_And_Bridging.js │ ├── D_Simple_Contagion.js │ ├── E_Complex_Contagion.js │ └── C_Networks.js ├── lib │ ├── Key.js │ ├── Sprite.js │ ├── Mouse.js │ ├── minpubsub.src.js │ └── helpers.js ├── slideshow │ ├── SimUI.js │ ├── Scratch.js │ ├── Translations.js │ ├── Pencil.js │ ├── Navigation.js │ ├── Modal.js │ ├── Preloader.js │ ├── Boxes.js │ ├── Slideshow.js │ └── SandboxUI.js ├── main.js └── sim │ ├── Connection.js │ ├── ConnectorCutter.js │ └── Peep.js ├── translations.txt ├── README.md └── LICENSE /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/favicon.png -------------------------------------------------------------------------------- /audio/bonk.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/bonk.mp3 -------------------------------------------------------------------------------- /audio/boom.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/boom.mp3 -------------------------------------------------------------------------------- /audio/pop.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/pop.mp3 -------------------------------------------------------------------------------- /audio/chimes.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/chimes.mp3 -------------------------------------------------------------------------------- /audio/party.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/party.mp3 -------------------------------------------------------------------------------- /audio/pencil.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/pencil.mp3 -------------------------------------------------------------------------------- /audio/pluck0.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/pluck0.mp3 -------------------------------------------------------------------------------- /audio/pluck1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/pluck1.mp3 -------------------------------------------------------------------------------- /audio/pluck2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/pluck2.mp3 -------------------------------------------------------------------------------- /audio/pluck3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/pluck3.mp3 -------------------------------------------------------------------------------- /audio/snip0.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/snip0.mp3 -------------------------------------------------------------------------------- /audio/snip1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/snip1.mp3 -------------------------------------------------------------------------------- /audio/snip2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/snip2.mp3 -------------------------------------------------------------------------------- /audio/trash.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/trash.mp3 -------------------------------------------------------------------------------- /social/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/social/thumb.png -------------------------------------------------------------------------------- /sprites/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/line.png -------------------------------------------------------------------------------- /sprites/nasa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/nasa.png -------------------------------------------------------------------------------- /audio/bg_music.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/bg_music.mp3 -------------------------------------------------------------------------------- /audio/button0.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/button0.mp3 -------------------------------------------------------------------------------- /audio/button1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/button1.mp3 -------------------------------------------------------------------------------- /audio/button2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/button2.mp3 -------------------------------------------------------------------------------- /audio/contagion.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/contagion.mp3 -------------------------------------------------------------------------------- /audio/squeak_up.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/squeak_up.mp3 -------------------------------------------------------------------------------- /sprites/peeps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/peeps.png -------------------------------------------------------------------------------- /sprites/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/pencil.png -------------------------------------------------------------------------------- /sprites/scratch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/scratch.png -------------------------------------------------------------------------------- /audio/party_short.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/party_short.mp3 -------------------------------------------------------------------------------- /audio/scratch_in.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/scratch_in.mp3 -------------------------------------------------------------------------------- /audio/scratch_out.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/scratch_out.mp3 -------------------------------------------------------------------------------- /audio/squeak_down.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/squeak_down.mp3 -------------------------------------------------------------------------------- /sprites/bonus/ee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/ee.png -------------------------------------------------------------------------------- /sprites/bonus/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/map.png -------------------------------------------------------------------------------- /sprites/confetti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/confetti.png -------------------------------------------------------------------------------- /sprites/icons/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/icons/red.png -------------------------------------------------------------------------------- /sprites/ui/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/ui/arrow.png -------------------------------------------------------------------------------- /sprites/ui/bonus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/ui/bonus.png -------------------------------------------------------------------------------- /sprites/ui/sound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/ui/sound.png -------------------------------------------------------------------------------- /audio/pencil_short.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/audio/pencil_short.mp3 -------------------------------------------------------------------------------- /sprites/bonus/trust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/trust.png -------------------------------------------------------------------------------- /sprites/button_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/button_large.png -------------------------------------------------------------------------------- /sprites/icons/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/icons/blue.png -------------------------------------------------------------------------------- /sprites/icons/gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/icons/gray.png -------------------------------------------------------------------------------- /sprites/icons/yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/icons/yellow.png -------------------------------------------------------------------------------- /sprites/red_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/red_button.png -------------------------------------------------------------------------------- /sprites/small_world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/small_world.png -------------------------------------------------------------------------------- /sprites/ui/sharing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/ui/sharing.png -------------------------------------------------------------------------------- /supporters/peeps/ljt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/ljt.png -------------------------------------------------------------------------------- /sprites/bonus/polygons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/polygons.png -------------------------------------------------------------------------------- /sprites/sandbox_tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/sandbox_tools.png -------------------------------------------------------------------------------- /supporters/peeps/nick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/nick.png -------------------------------------------------------------------------------- /supporters/peeps/noel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/noel.png -------------------------------------------------------------------------------- /supporters/polygons/c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/c.png -------------------------------------------------------------------------------- /supporters/polygons/m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/m.png -------------------------------------------------------------------------------- /css/PatrickHand-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/css/PatrickHand-Regular.ttf -------------------------------------------------------------------------------- /sprites/bonus/connected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/connected.png -------------------------------------------------------------------------------- /sprites/bonus/connection1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/connection1.png -------------------------------------------------------------------------------- /sprites/bonus/connection2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/connection2.png -------------------------------------------------------------------------------- /sprites/bonus/contagion1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/contagion1.png -------------------------------------------------------------------------------- /sprites/bonus/contagion2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/contagion2.png -------------------------------------------------------------------------------- /sprites/bonus/contagion3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/contagion3.png -------------------------------------------------------------------------------- /sprites/bonus/contagion4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/contagion4.png -------------------------------------------------------------------------------- /sprites/bonus/surowieki.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/bonus/surowieki.jpg -------------------------------------------------------------------------------- /sprites/tutorial_connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/tutorial_connect.png -------------------------------------------------------------------------------- /supporters/polygons/aaron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/aaron.png -------------------------------------------------------------------------------- /supporters/polygons/brian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/brian.png -------------------------------------------------------------------------------- /supporters/polygons/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/green.png -------------------------------------------------------------------------------- /supporters/polygons/jack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jack.png -------------------------------------------------------------------------------- /supporters/polygons/laura.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/laura.png -------------------------------------------------------------------------------- /supporters/polygons/ljt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/ljt.png -------------------------------------------------------------------------------- /supporters/polygons/mga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/mga.png -------------------------------------------------------------------------------- /supporters/polygons/mikey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/mikey.png -------------------------------------------------------------------------------- /supporters/polygons/nick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/nick.png -------------------------------------------------------------------------------- /supporters/polygons/noel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/noel.png -------------------------------------------------------------------------------- /supporters/polygons/sean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sean.png -------------------------------------------------------------------------------- /sprites/tutorial_disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/sprites/tutorial_disconnect.png -------------------------------------------------------------------------------- /supporters/peeps/andy_ellis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/andy_ellis.png -------------------------------------------------------------------------------- /supporters/peeps/ben_mathes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/ben_mathes.png -------------------------------------------------------------------------------- /supporters/peeps/joe_sevits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/joe_sevits.png -------------------------------------------------------------------------------- /supporters/peeps/sean_riley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/sean_riley.png -------------------------------------------------------------------------------- /supporters/peeps/yuhan_kuo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/yuhan_kuo.png -------------------------------------------------------------------------------- /supporters/peeps/zach_smith.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/zach_smith.png -------------------------------------------------------------------------------- /supporters/polygons/alex_g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/alex_g.png -------------------------------------------------------------------------------- /supporters/polygons/dave_tu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/dave_tu.png -------------------------------------------------------------------------------- /supporters/polygons/dominc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/dominc.png -------------------------------------------------------------------------------- /supporters/polygons/grvling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/grvling.png -------------------------------------------------------------------------------- /supporters/polygons/jaakko.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jaakko.png -------------------------------------------------------------------------------- /supporters/polygons/kailys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/kailys.png -------------------------------------------------------------------------------- /supporters/polygons/macdiva.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/macdiva.png -------------------------------------------------------------------------------- /supporters/polygons/maciej.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/maciej.png -------------------------------------------------------------------------------- /supporters/polygons/nikita.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/nikita.png -------------------------------------------------------------------------------- /supporters/polygons/quartz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/quartz.png -------------------------------------------------------------------------------- /supporters/polygons/s_smith.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/s_smith.png -------------------------------------------------------------------------------- /supporters/polygons/sal_go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sal_go.png -------------------------------------------------------------------------------- /supporters/peeps/aimee_jarboe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/aimee_jarboe.png -------------------------------------------------------------------------------- /supporters/peeps/chad_sansing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/chad_sansing.png -------------------------------------------------------------------------------- /supporters/peeps/dylan_field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/dylan_field.png -------------------------------------------------------------------------------- /supporters/peeps/kate_fractal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/kate_fractal.png -------------------------------------------------------------------------------- /supporters/peeps/matt_hughes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/matt_hughes.png -------------------------------------------------------------------------------- /supporters/peeps/michael_duke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/michael_duke.png -------------------------------------------------------------------------------- /supporters/peeps/michael_huff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/michael_huff.png -------------------------------------------------------------------------------- /supporters/peeps/natalie_sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/natalie_sun.png -------------------------------------------------------------------------------- /supporters/peeps/rafael_ffont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/rafael_ffont.png -------------------------------------------------------------------------------- /supporters/peeps/travis_ross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/travis_ross.png -------------------------------------------------------------------------------- /supporters/polygons/alex_mole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/alex_mole.png -------------------------------------------------------------------------------- /supporters/polygons/amy_fuchs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/amy_fuchs.png -------------------------------------------------------------------------------- /supporters/polygons/andy_ellis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/andy_ellis.png -------------------------------------------------------------------------------- /supporters/polygons/aran_jger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/aran_jger.png -------------------------------------------------------------------------------- /supporters/polygons/ben_kraft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/ben_kraft.png -------------------------------------------------------------------------------- /supporters/polygons/ben_mathes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/ben_mathes.png -------------------------------------------------------------------------------- /supporters/polygons/bob_wise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/bob_wise.png -------------------------------------------------------------------------------- /supporters/polygons/boondoggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/boondoggle.png -------------------------------------------------------------------------------- /supporters/polygons/cathy_deng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/cathy_deng.png -------------------------------------------------------------------------------- /supporters/polygons/ceceron44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/ceceron44.png -------------------------------------------------------------------------------- /supporters/polygons/cyrus_levy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/cyrus_levy.png -------------------------------------------------------------------------------- /supporters/polygons/evan_rocha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/evan_rocha.png -------------------------------------------------------------------------------- /supporters/polygons/gui_ambros.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/gui_ambros.png -------------------------------------------------------------------------------- /supporters/polygons/joe_sevits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/joe_sevits.png -------------------------------------------------------------------------------- /supporters/polygons/josh_leong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/josh_leong.png -------------------------------------------------------------------------------- /supporters/polygons/lexszero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/lexszero.png -------------------------------------------------------------------------------- /supporters/polygons/mary_bush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/mary_bush.png -------------------------------------------------------------------------------- /supporters/polygons/nat_alison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/nat_alison.png -------------------------------------------------------------------------------- /supporters/polygons/raspbeguy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/raspbeguy.png -------------------------------------------------------------------------------- /supporters/polygons/rob_napier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rob_napier.png -------------------------------------------------------------------------------- /supporters/polygons/rohit_bhat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rohit_bhat.png -------------------------------------------------------------------------------- /supporters/polygons/sam_dorios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sam_dorios.png -------------------------------------------------------------------------------- /supporters/polygons/sam_remis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sam_remis.png -------------------------------------------------------------------------------- /supporters/polygons/sean_riley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sean_riley.png -------------------------------------------------------------------------------- /supporters/polygons/settworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/settworks.png -------------------------------------------------------------------------------- /supporters/polygons/tom_lieber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/tom_lieber.png -------------------------------------------------------------------------------- /supporters/polygons/upidaisy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/upidaisy.png -------------------------------------------------------------------------------- /supporters/polygons/yuhan_kuo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/yuhan_kuo.png -------------------------------------------------------------------------------- /supporters/polygons/zach_smith.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/zach_smith.png -------------------------------------------------------------------------------- /supporters/peeps/andrew_grondin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/andrew_grondin.png -------------------------------------------------------------------------------- /supporters/peeps/david_e_weekly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/david_e_weekly.png -------------------------------------------------------------------------------- /supporters/peeps/jared_cosulich.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/jared_cosulich.png -------------------------------------------------------------------------------- /supporters/peeps/phil_dougherty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/phil_dougherty.png -------------------------------------------------------------------------------- /supporters/peeps/srini_kadamati.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/srini_kadamati.png -------------------------------------------------------------------------------- /supporters/polygons/adam_zeiner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/adam_zeiner.png -------------------------------------------------------------------------------- /supporters/polygons/aiden_clack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/aiden_clack.png -------------------------------------------------------------------------------- /supporters/polygons/aimee_jarboe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/aimee_jarboe.png -------------------------------------------------------------------------------- /supporters/polygons/alejo_amiras.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/alejo_amiras.png -------------------------------------------------------------------------------- /supporters/polygons/alex_dytrych.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/alex_dytrych.png -------------------------------------------------------------------------------- /supporters/polygons/amy_traylor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/amy_traylor.png -------------------------------------------------------------------------------- /supporters/polygons/aria_minaei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/aria_minaei.png -------------------------------------------------------------------------------- /supporters/polygons/brian_lange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/brian_lange.png -------------------------------------------------------------------------------- /supporters/polygons/cedric_rossi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/cedric_rossi.png -------------------------------------------------------------------------------- /supporters/polygons/chad_sansing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/chad_sansing.png -------------------------------------------------------------------------------- /supporters/polygons/chris_makler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/chris_makler.png -------------------------------------------------------------------------------- /supporters/polygons/colin_liotta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/colin_liotta.png -------------------------------------------------------------------------------- /supporters/polygons/cristy_stone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/cristy_stone.png -------------------------------------------------------------------------------- /supporters/polygons/curtis_frye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/curtis_frye.png -------------------------------------------------------------------------------- /supporters/polygons/da_liberman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/da_liberman.png -------------------------------------------------------------------------------- /supporters/polygons/dave_mcclure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/dave_mcclure.png -------------------------------------------------------------------------------- /supporters/polygons/dylan_field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/dylan_field.png -------------------------------------------------------------------------------- /supporters/polygons/eli_jeschke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/eli_jeschke.png -------------------------------------------------------------------------------- /supporters/polygons/evan_shulman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/evan_shulman.png -------------------------------------------------------------------------------- /supporters/polygons/fred_ehrsam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/fred_ehrsam.png -------------------------------------------------------------------------------- /supporters/polygons/fred_tschepp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/fred_tschepp.png -------------------------------------------------------------------------------- /supporters/polygons/glen_e_ivey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/glen_e_ivey.png -------------------------------------------------------------------------------- /supporters/polygons/greg_nelson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/greg_nelson.png -------------------------------------------------------------------------------- /supporters/polygons/hilary_fried.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/hilary_fried.png -------------------------------------------------------------------------------- /supporters/polygons/idahosa_ness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/idahosa_ness.png -------------------------------------------------------------------------------- /supporters/polygons/istvn_hamar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/istvn_hamar.png -------------------------------------------------------------------------------- /supporters/polygons/ivo_murrell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/ivo_murrell.png -------------------------------------------------------------------------------- /supporters/polygons/jacob_feala.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jacob_feala.png -------------------------------------------------------------------------------- /supporters/polygons/jasmine_ren.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jasmine_ren.png -------------------------------------------------------------------------------- /supporters/polygons/jessica_osio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jessica_osio.png -------------------------------------------------------------------------------- /supporters/polygons/joe_shumaker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/joe_shumaker.png -------------------------------------------------------------------------------- /supporters/polygons/jonathan_ng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jonathan_ng.png -------------------------------------------------------------------------------- /supporters/polygons/josh_comeau.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/josh_comeau.png -------------------------------------------------------------------------------- /supporters/polygons/josh_koenig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/josh_koenig.png -------------------------------------------------------------------------------- /supporters/polygons/julie_franke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/julie_franke.png -------------------------------------------------------------------------------- /supporters/polygons/karen_cooper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/karen_cooper.png -------------------------------------------------------------------------------- /supporters/polygons/kate_fractal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/kate_fractal.png -------------------------------------------------------------------------------- /supporters/polygons/leopard_dan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/leopard_dan.png -------------------------------------------------------------------------------- /supporters/polygons/linda_liukas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/linda_liukas.png -------------------------------------------------------------------------------- /supporters/polygons/lucas_garron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/lucas_garron.png -------------------------------------------------------------------------------- /supporters/polygons/matt_hughes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/matt_hughes.png -------------------------------------------------------------------------------- /supporters/polygons/michael_duke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/michael_duke.png -------------------------------------------------------------------------------- /supporters/polygons/michael_huff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/michael_huff.png -------------------------------------------------------------------------------- /supporters/polygons/natalie_sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/natalie_sun.png -------------------------------------------------------------------------------- /supporters/polygons/nimrod_kimhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/nimrod_kimhi.png -------------------------------------------------------------------------------- /supporters/polygons/pablo_molins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/pablo_molins.png -------------------------------------------------------------------------------- /supporters/polygons/paul_daoust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/paul_daoust.png -------------------------------------------------------------------------------- /supporters/polygons/paul_sztajer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/paul_sztajer.png -------------------------------------------------------------------------------- /supporters/polygons/peter_kadlot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/peter_kadlot.png -------------------------------------------------------------------------------- /supporters/polygons/rae_mcintosh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rae_mcintosh.png -------------------------------------------------------------------------------- /supporters/polygons/rafael_ffont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rafael_ffont.png -------------------------------------------------------------------------------- /supporters/polygons/robert_aran.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/robert_aran.png -------------------------------------------------------------------------------- /supporters/polygons/rupert_moore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rupert_moore.png -------------------------------------------------------------------------------- /supporters/polygons/sam_prinssen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sam_prinssen.png -------------------------------------------------------------------------------- /supporters/polygons/shreeya_goel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/shreeya_goel.png -------------------------------------------------------------------------------- /supporters/polygons/steve_krouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/steve_krouse.png -------------------------------------------------------------------------------- /supporters/polygons/steve_ryman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/steve_ryman.png -------------------------------------------------------------------------------- /supporters/polygons/tal_rotbart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/tal_rotbart.png -------------------------------------------------------------------------------- /supporters/polygons/tamir_bahar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/tamir_bahar.png -------------------------------------------------------------------------------- /supporters/polygons/todd_siegel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/todd_siegel.png -------------------------------------------------------------------------------- /supporters/polygons/toph_tucker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/toph_tucker.png -------------------------------------------------------------------------------- /supporters/polygons/travis_ross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/travis_ross.png -------------------------------------------------------------------------------- /supporters/polygons/yinhung_hsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/yinhung_hsu.png -------------------------------------------------------------------------------- /supporters/peeps/christopher_rodier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/peeps/christopher_rodier.png -------------------------------------------------------------------------------- /supporters/polygons/abhishek_modi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/abhishek_modi.png -------------------------------------------------------------------------------- /supporters/polygons/aditya_bhargava.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/aditya_bhargava.png -------------------------------------------------------------------------------- /supporters/polygons/aiman_josefsson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/aiman_josefsson.png -------------------------------------------------------------------------------- /supporters/polygons/andrew_grondin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/andrew_grondin.png -------------------------------------------------------------------------------- /supporters/polygons/anshul_dhawan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/anshul_dhawan.png -------------------------------------------------------------------------------- /supporters/polygons/artwalks_europe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/artwalks_europe.png -------------------------------------------------------------------------------- /supporters/polygons/bohdan_makohin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/bohdan_makohin.png -------------------------------------------------------------------------------- /supporters/polygons/brianna_bergen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/brianna_bergen.png -------------------------------------------------------------------------------- /supporters/polygons/bruce_steinberg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/bruce_steinberg.png -------------------------------------------------------------------------------- /supporters/polygons/caelyn_mcaulay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/caelyn_mcaulay.png -------------------------------------------------------------------------------- /supporters/polygons/charlie_stigler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/charlie_stigler.png -------------------------------------------------------------------------------- /supporters/polygons/chris_hallacy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/chris_hallacy.png -------------------------------------------------------------------------------- /supporters/polygons/clive_freeman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/clive_freeman.png -------------------------------------------------------------------------------- /supporters/polygons/colin_anderson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/colin_anderson.png -------------------------------------------------------------------------------- /supporters/polygons/david_e_weekly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/david_e_weekly.png -------------------------------------------------------------------------------- /supporters/polygons/david_sallmann.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/david_sallmann.png -------------------------------------------------------------------------------- /supporters/polygons/elmar_schlueter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/elmar_schlueter.png -------------------------------------------------------------------------------- /supporters/polygons/eric_chisholm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/eric_chisholm.png -------------------------------------------------------------------------------- /supporters/polygons/fiona_nielsen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/fiona_nielsen.png -------------------------------------------------------------------------------- /supporters/polygons/freddie_firth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/freddie_firth.png -------------------------------------------------------------------------------- /supporters/polygons/fritz_solares.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/fritz_solares.png -------------------------------------------------------------------------------- /supporters/polygons/harry_brisson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/harry_brisson.png -------------------------------------------------------------------------------- /supporters/polygons/igor_krawczuk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/igor_krawczuk.png -------------------------------------------------------------------------------- /supporters/polygons/industrialrobot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/industrialrobot.png -------------------------------------------------------------------------------- /supporters/polygons/jacopo_cascioli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jacopo_cascioli.png -------------------------------------------------------------------------------- /supporters/polygons/jamieson_taylor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jamieson_taylor.png -------------------------------------------------------------------------------- /supporters/polygons/jared_cosulich.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jared_cosulich.png -------------------------------------------------------------------------------- /supporters/polygons/jason_crawford.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jason_crawford.png -------------------------------------------------------------------------------- /supporters/polygons/jeaneudes_denis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jeaneudes_denis.png -------------------------------------------------------------------------------- /supporters/polygons/jesper_the_end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jesper_the_end.png -------------------------------------------------------------------------------- /supporters/polygons/josef_komenda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/josef_komenda.png -------------------------------------------------------------------------------- /supporters/polygons/joshua_horowitz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/joshua_horowitz.png -------------------------------------------------------------------------------- /supporters/polygons/kaitlin_smith.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/kaitlin_smith.png -------------------------------------------------------------------------------- /supporters/polygons/kendra_lockman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/kendra_lockman.png -------------------------------------------------------------------------------- /supporters/polygons/kevin_zollman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/kevin_zollman.png -------------------------------------------------------------------------------- /supporters/polygons/kumara_uttara.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/kumara_uttara.png -------------------------------------------------------------------------------- /supporters/polygons/laura_baldwin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/laura_baldwin.png -------------------------------------------------------------------------------- /supporters/polygons/leslie_robinson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/leslie_robinson.png -------------------------------------------------------------------------------- /supporters/polygons/lukas_wegmann.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/lukas_wegmann.png -------------------------------------------------------------------------------- /supporters/polygons/marconi_pereira.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/marconi_pereira.png -------------------------------------------------------------------------------- /supporters/polygons/matthew_weber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/matthew_weber.png -------------------------------------------------------------------------------- /supporters/polygons/maxim_sidorov.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/maxim_sidorov.png -------------------------------------------------------------------------------- /supporters/polygons/michael_donatz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/michael_donatz.png -------------------------------------------------------------------------------- /supporters/polygons/michael_handler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/michael_handler.png -------------------------------------------------------------------------------- /supporters/polygons/mikkel_snyder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/mikkel_snyder.png -------------------------------------------------------------------------------- /supporters/polygons/molly_mcfadden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/molly_mcfadden.png -------------------------------------------------------------------------------- /supporters/polygons/naomi_alderman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/naomi_alderman.png -------------------------------------------------------------------------------- /supporters/polygons/nelson_crespo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/nelson_crespo.png -------------------------------------------------------------------------------- /supporters/polygons/nick_gallegos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/nick_gallegos.png -------------------------------------------------------------------------------- /supporters/polygons/noah_richards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/noah_richards.png -------------------------------------------------------------------------------- /supporters/polygons/patrick_bobell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/patrick_bobell.png -------------------------------------------------------------------------------- /supporters/polygons/phil_dougherty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/phil_dougherty.png -------------------------------------------------------------------------------- /supporters/polygons/postmillenial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/postmillenial.png -------------------------------------------------------------------------------- /supporters/polygons/raymond_keller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/raymond_keller.png -------------------------------------------------------------------------------- /supporters/polygons/rebecca_wigandt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rebecca_wigandt.png -------------------------------------------------------------------------------- /supporters/polygons/rob_mckaughan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rob_mckaughan.png -------------------------------------------------------------------------------- /supporters/polygons/robert_duncan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/robert_duncan.png -------------------------------------------------------------------------------- /supporters/polygons/rory_sutherland.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/rory_sutherland.png -------------------------------------------------------------------------------- /supporters/polygons/sara_hekimian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sara_hekimian.png -------------------------------------------------------------------------------- /supporters/polygons/scott_donaldson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/scott_donaldson.png -------------------------------------------------------------------------------- /supporters/polygons/serena_casanova.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/serena_casanova.png -------------------------------------------------------------------------------- /supporters/polygons/sergiy_protsiv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/sergiy_protsiv.png -------------------------------------------------------------------------------- /supporters/polygons/srini_kadamati.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/srini_kadamati.png -------------------------------------------------------------------------------- /supporters/polygons/steve_waldman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/steve_waldman.png -------------------------------------------------------------------------------- /supporters/polygons/teodor_zhechev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/teodor_zhechev.png -------------------------------------------------------------------------------- /supporters/polygons/toby_schachman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/toby_schachman.png -------------------------------------------------------------------------------- /supporters/polygons/trevor_haldenby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/trevor_haldenby.png -------------------------------------------------------------------------------- /supporters/polygons/tudor_iliescu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/tudor_iliescu.png -------------------------------------------------------------------------------- /supporters/polygons/william_ohanley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/william_ohanley.png -------------------------------------------------------------------------------- /supporters/polygons/wouter_slegers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/wouter_slegers.png -------------------------------------------------------------------------------- /supporters/polygons/yates_buckley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/yates_buckley.png -------------------------------------------------------------------------------- /supporters/polygons/yury_melnichek.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/yury_melnichek.png -------------------------------------------------------------------------------- /supporters/polygons/zan_armstrong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/zan_armstrong.png -------------------------------------------------------------------------------- /supporters/polygons/alexander_zacherl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/alexander_zacherl.png -------------------------------------------------------------------------------- /supporters/polygons/alexandre_barret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/alexandre_barret.png -------------------------------------------------------------------------------- /supporters/polygons/andrea_di_biagio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/andrea_di_biagio.png -------------------------------------------------------------------------------- /supporters/polygons/animation_at_work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/animation_at_work.png -------------------------------------------------------------------------------- /supporters/polygons/anthony_pecorella.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/anthony_pecorella.png -------------------------------------------------------------------------------- /supporters/polygons/benjamin_lindsay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/benjamin_lindsay.png -------------------------------------------------------------------------------- /supporters/polygons/christopher_goes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/christopher_goes.png -------------------------------------------------------------------------------- /supporters/polygons/dag_frode_solberg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/dag_frode_solberg.png -------------------------------------------------------------------------------- /supporters/polygons/iain_kirkpatrick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/iain_kirkpatrick.png -------------------------------------------------------------------------------- /supporters/polygons/jan_van_nigtevegt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jan_van_nigtevegt.png -------------------------------------------------------------------------------- /supporters/polygons/kelvin_nishikawa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/kelvin_nishikawa.png -------------------------------------------------------------------------------- /supporters/polygons/matthew_campbell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/matthew_campbell.png -------------------------------------------------------------------------------- /supporters/polygons/michael_merchant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/michael_merchant.png -------------------------------------------------------------------------------- /supporters/polygons/natalie_rothfels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/natalie_rothfels.png -------------------------------------------------------------------------------- /supporters/polygons/patrick_henderson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/patrick_henderson.png -------------------------------------------------------------------------------- /supporters/polygons/reed_copperstrand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/reed_copperstrand.png -------------------------------------------------------------------------------- /supporters/polygons/shakir_alshareef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/shakir_alshareef.png -------------------------------------------------------------------------------- /supporters/polygons/silviu_strliciuc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/silviu_strliciuc.png -------------------------------------------------------------------------------- /supporters/polygons/thomas_ballinger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/thomas_ballinger.png -------------------------------------------------------------------------------- /supporters/polygons/william_b_everett.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/william_b_everett.png -------------------------------------------------------------------------------- /supporters/polygons/christopher_ferrie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/christopher_ferrie.png -------------------------------------------------------------------------------- /supporters/polygons/christopher_rodier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/christopher_rodier.png -------------------------------------------------------------------------------- /supporters/polygons/dinos_papadopoulos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/dinos_papadopoulos.png -------------------------------------------------------------------------------- /supporters/polygons/florencia_herra_vega.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/florencia_herra_vega.png -------------------------------------------------------------------------------- /supporters/polygons/jacob_james_leaney.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jacob_james_leaney.png -------------------------------------------------------------------------------- /supporters/polygons/josh_cheeseness_bush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/josh_cheeseness_bush.png -------------------------------------------------------------------------------- /supporters/polygons/juan_ignacio_terraza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/juan_ignacio_terraza.png -------------------------------------------------------------------------------- /supporters/polygons/mikayla_hutchinson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/mikayla_hutchinson.png -------------------------------------------------------------------------------- /supporters/polygons/nishanth_sudharsanam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/nishanth_sudharsanam.png -------------------------------------------------------------------------------- /supporters/polygons/stefano_baccianella.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/stefano_baccianella.png -------------------------------------------------------------------------------- /supporters/polygons/allison_cliftjennings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/allison_cliftjennings.png -------------------------------------------------------------------------------- /supporters/polygons/gabriel_barbosa_nunes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/gabriel_barbosa_nunes.png -------------------------------------------------------------------------------- /supporters/polygons/iago_medeiros_cordeiro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/iago_medeiros_cordeiro.png -------------------------------------------------------------------------------- /supporters/polygons/caio_vinicius_do_nascimento.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/caio_vinicius_do_nascimento.png -------------------------------------------------------------------------------- /supporters/polygons/jacob_christian_munchandersen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/crowds/master/supporters/polygons/jacob_christian_munchandersen.png -------------------------------------------------------------------------------- /js/chapters/I_Credits.js: -------------------------------------------------------------------------------- 1 | // 0 - INTRODUCTION 2 | SLIDES.push( 3 | { 4 | chapter: "Credits", 5 | clear:true, 6 | add:[ 7 | 8 | // Background 9 | { 10 | type:"box", 11 | background:"#222" 12 | }, 13 | 14 | // CREDITS 15 | { 16 | type:"box", 17 | text:"credits", x:0, y:0, w:960, h:540 18 | } 19 | 20 | ] 21 | 22 | } 23 | ); -------------------------------------------------------------------------------- /js/lib/Key.js: -------------------------------------------------------------------------------- 1 | ////////////////////////////// 2 | // KEYS (it's a secret) ////// 3 | ////////////////////////////// 4 | 5 | var KEYS = { 6 | 32: "space", 7 | 49: "1", 8 | 50: "2", 9 | 8: "delete", 10 | 27: "escape" 11 | }; 12 | 13 | window.addEventListener("keydown", function(event){ 14 | var key = KEYS[event.keyCode]; 15 | if(key) publish("key/down/"+key); 16 | }); 17 | 18 | window.addEventListener("keyup", function(event){ 19 | var key = KEYS[event.keyCode]; 20 | if(key) publish("key/up/"+key); 21 | }); -------------------------------------------------------------------------------- /js/chapters/J_Sandbox.js: -------------------------------------------------------------------------------- 1 | SLIDES.push( 2 | { 3 | chapter: "Sandbox", 4 | clear:true, 5 | 6 | add:[ 7 | 8 | // The fullscreen simulation 9 | { 10 | type:"sim", 11 | x:0, y:0, 12 | fullscreen: true, 13 | network: { 14 | "contagion":0.25, 15 | "peeps":[[506,195,1],[621,270,0],[724,194,0]], 16 | "connections":[[0,1,0],[1,2,0]] 17 | }, 18 | }, 19 | 20 | // The Sandbox UI 21 | { 22 | type:"box", 23 | x:0, y:0, 24 | sandbox:true 25 | }, 26 | 27 | // Simulation UI 28 | { 29 | type:"box", 30 | x:35, y:400, 31 | sim_ui:"red" 32 | }, 33 | 34 | // Words 35 | { 36 | type:"box", 37 | text:"sandbox_caption", 38 | x:660, y:500, w:300, h:40, 39 | align:"right" 40 | } 41 | 42 | 43 | ] 44 | 45 | } 46 | ); -------------------------------------------------------------------------------- /js/chapters/B_Introduction.js: -------------------------------------------------------------------------------- 1 | SLIDES.push( 2 | 3 | { 4 | chapter: "Introduction", 5 | 6 | remove:[ 7 | {type:"box", id:"title"}, 8 | {type:"box", id:"button"} 9 | ], 10 | 11 | add:[ 12 | 13 | // Splash 14 | { 15 | ONLY_IF_IT_DOESNT_ALREADY_EXIST: true, 16 | type:"sim", 17 | x:960/2, y:540/2, 18 | fullscreen: true, 19 | network: SPLASH_NETWORK, 20 | options:{ 21 | splash: true, 22 | randomStart: 20 23 | } 24 | }, 25 | 26 | // Words 27 | { 28 | type:"box", 29 | id:"intro", 30 | text:"intro", x:180, y:0, w:600, h:540, align:"center" 31 | }, 32 | 33 | ] 34 | 35 | }, 36 | { 37 | remove:[ 38 | { type:"box", id:"intro" } 39 | ], 40 | add:[ 41 | { 42 | type:"box", 43 | id:"intro_2", 44 | text:"intro_2", x:180, y:0, w:600, h:540, align:"center" 45 | } 46 | ] 47 | } 48 | 49 | ); -------------------------------------------------------------------------------- /js/lib/Sprite.js: -------------------------------------------------------------------------------- 1 | function Sprite(config){ 2 | 3 | var self = this; 4 | self.config = config; 5 | 6 | // Properties... 7 | self.x = 0; 8 | self.y = 0; 9 | self.pivotX = 0; 10 | self.pivotY = 0; 11 | self.scale = null; 12 | self.scaleX = 1; 13 | self.scaleY = 1; 14 | self.rotation = 0; // radians 15 | 16 | // Frames 17 | self.currentFrame = 0; 18 | self.totalFrames = config.frames; 19 | self.nextFrame = function(){ 20 | self.currentFrame = (self.currentFrame+1)%self.totalFrames; 21 | }; 22 | self.gotoFrame = function(frame){ 23 | self.currentFrame = frame; 24 | }; 25 | 26 | // Draw 27 | self.draw = function(ctx){ 28 | 29 | var sw = config.sw; 30 | var sh = config.sh; 31 | var sx = self.currentFrame*sw; 32 | var sy = 0; 33 | 34 | ctx.save(); 35 | ctx.translate(self.x, self.y); 36 | ctx.rotate(self.rotation); 37 | if(self.scale){ 38 | ctx.scale(self.scale, self.scale); 39 | }else{ 40 | ctx.scale(self.scaleX, self.scaleY); 41 | } 42 | ctx.translate(-self.pivotX, -self.pivotY); 43 | var image = IMAGES[config.img]; 44 | ctx.drawImage(image, sx, sy, sw, sh, 0, 0, sw, sh); 45 | ctx.restore(); 46 | 47 | }; 48 | 49 | } -------------------------------------------------------------------------------- /translations.txt: -------------------------------------------------------------------------------- 1 | // Once you've finished your translation, 2 | // the website needs to "know" it exists! 3 | // This text file is how the website "knows". 4 | // 5 | // First, look up the language you're translating to on this page: 6 | // https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes 7 | // 8 | // Then, at the bottom of this file, enter on a new line: 9 | // [two-letter code]: [native name of language] 10 | // For example: 11 | // en: English 12 | // de: Deutsch 13 | // zh: 中文 14 | // ar: العربية 15 | // 16 | // (Note: if you paste the native name of a right-to-left language here, 17 | // it might show up as reversed here, but it'll show correctly on the website) 18 | // Also, make sure the .html file of your translation 19 | // uses the two-letter code, like "de.html", "ar.html", "zh.html" 20 | // 21 | // Thank you again so much! :) 22 | // Once you're done, send a Pull Request to the GitHub repo 23 | // so I can add your translation. Instructions are here: 24 | // https://github.com/ncase/crowds#how-to-translate-this-thing 25 | 26 | ///////////////////////////// 27 | // AVAILABLE TRANSLATIONS: // 28 | ///////////////////////////// 29 | 30 | en: English -------------------------------------------------------------------------------- /js/slideshow/SimUI.js: -------------------------------------------------------------------------------- 1 | function SimUI(container, color){ 2 | 3 | var self = this; 4 | self.container = container; 5 | self.container.classList.add("sim_ui"); 6 | 7 | // START / NEXT 8 | var startButton = document.createElement("div"); 9 | startButton.id = "start_button"; 10 | self.container.appendChild(startButton); 11 | startButton.onclick = function(event){ 12 | publish("sound/button"); 13 | if(!Simulations.IS_RUNNING){ 14 | Simulations.IS_RUNNING = true; 15 | publish("sim/start"); 16 | }else{ 17 | Simulations.IS_RUNNING = false; 18 | publish("sim/stop"); 19 | } 20 | }; 21 | _stopPropButton(startButton); 22 | 23 | // Update button UI 24 | var _updateButtonUI = function(){ 25 | if(!Simulations.IS_RUNNING){ 26 | startButton.innerHTML = getWords("sim_start"); 27 | self.container.removeAttribute("active"); 28 | }else{ 29 | startButton.innerHTML = getWords("sim_stop"); 30 | self.container.setAttribute("active",true); 31 | } 32 | }; 33 | _updateButtonUI(); 34 | 35 | var _handler1 = subscribe("sim/start",_updateButtonUI); 36 | var _handler2 = subscribe("sim/stop",_updateButtonUI); 37 | self.container.kill = function(){ 38 | unsubscribe(_handler1); 39 | unsubscribe(_handler2); 40 | }; 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /js/slideshow/Scratch.js: -------------------------------------------------------------------------------- 1 | function Scratch(){ 2 | 3 | var self = this; 4 | self.canvas = $("#scratch"); 5 | self.ctx = self.canvas.getContext("2d"); 6 | 7 | // 711 x 400 8 | var w = 711; 9 | var h = 400; 10 | 11 | self.scratchIn = function(){ 12 | 13 | // SOUND! 14 | SOUNDS.scratch_in.play(); 15 | 16 | // anim 17 | self.startUpdateLoop(false, function(){ 18 | self.canvas.style.display = "none"; 19 | }); 20 | 21 | }; 22 | 23 | self.scratchOut = function(){ 24 | 25 | // SOUND! 26 | SOUNDS.scratch_in.play(); 27 | 28 | // anim 29 | self.canvas.style.display = "block"; 30 | self.startUpdateLoop(true); 31 | 32 | }; 33 | 34 | self.startUpdateLoop = function(out, callback){ 35 | var frame = 0; 36 | var xOffset = out ? 0 : w; 37 | var handle = subscribe("update", function(){ 38 | var yOffset = Math.floor(frame)*h; 39 | 40 | // Redraw canvas 41 | self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height); 42 | self.ctx.drawImage( 43 | IMAGES.scratch, 44 | xOffset, yOffset, w, h, 45 | 0, 0, w, h); 46 | 47 | // Staaaahhhhhp 48 | if(frame>19){ 49 | unsubscribe(handle); 50 | if(callback) callback(); 51 | return; 52 | } 53 | frame+=0.5; 54 | 55 | }); 56 | }; 57 | 58 | } -------------------------------------------------------------------------------- /js/slideshow/Translations.js: -------------------------------------------------------------------------------- 1 | window.TRANSLATIONS = []; 2 | window.ADD_YOUR_OWN_LINK = "https://github.com/ncase/crowds#how-to-translate-this-thing"; 3 | 4 | var r = new XMLHttpRequest(); 5 | r.open("GET", "translations.txt", true); 6 | r.onreadystatechange = function () { 7 | 8 | if(r.readyState != 4 || r.status != 200) return; 9 | 10 | // Parse available translations 11 | // Only lines of the form "nn: name" 12 | var response = r.responseText; 13 | var lines = response.split("\n"); 14 | var available = lines.filter(function(line){ 15 | return (/^\w\w\:?\s+(.+)/).test(line); // ww: wwwwww 16 | }); 17 | for(var i=0; ib.lang; 29 | }); 30 | 31 | // Show translations (if any) 32 | if(TRANSLATIONS.length>0){ 33 | var html = ""; 34 | html += getWords("translations_exist").toLowerCase(); 35 | html += " "+getWords("translations_add")+""; 36 | html += " | "; 37 | html += _createLinks(" · "); 38 | $("#translations").innerHTML = html; 39 | } 40 | 41 | }; 42 | r.send(); 43 | 44 | function _createLinks(separator){ 45 | var html = ""; 46 | for(var i=0; i0) html+=separator; 49 | html += ""; 50 | html += t.lang; 51 | html += ""; 52 | } 53 | return html; 54 | } -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | window.onload = function(){ 2 | 3 | // Start Preloading! 4 | publish("prepreload"); 5 | 6 | } 7 | 8 | subscribe("prepreload/done", function(){ 9 | 10 | // Bye Pre-Preloader! 11 | var pre_preloader = $("#pre_preloader"); 12 | pre_preloader.parentNode.removeChild(pre_preloader); 13 | 14 | // Setting up the main stuff 15 | window.slideshow = new Slideshow(); 16 | window.pencil = new Pencil(); 17 | window.navigation = new Navigation(); 18 | 19 | // Initializing the Mouse 20 | Mouse.init(document.body); 21 | 22 | // Animation loop IS update loop for now, whatever 23 | function update(){ 24 | 25 | // Update 26 | slideshow.update(); 27 | pencil.update(); 28 | Mouse.update(); 29 | 30 | // Draw 31 | slideshow.draw(); 32 | pencil.draw(); 33 | 34 | // Update 35 | publish("update"); 36 | 37 | window.requestAnimationFrame(update); 38 | 39 | } 40 | window.requestAnimationFrame(update); 41 | 42 | // Go to THE SPLASH 43 | slideshow.gotoChapter("Preloader"); 44 | 45 | // HACK - MOBILE IS HORRIBLE 46 | $all("a").forEach(function(a){ 47 | a.ontouchstart = function(event){ 48 | event.stopPropagation(); 49 | }; // so you CAN click links 50 | }); 51 | 52 | }); 53 | 54 | subscribe("START", function(){ 55 | 56 | // Music 57 | SOUNDS.bg_music.volume(0.5); 58 | SOUNDS.bg_music.loop(true); 59 | SOUNDS.bg_music.play(); 60 | 61 | // Hide translations, show navigation 62 | $("#translations").style.display = "none"; 63 | $("#navigation").style.display = "block"; 64 | 65 | // Show Skip Button 66 | var skippy = $("#skip"); 67 | skippy.style.display = "block"; 68 | skippy.onclick = function(){ 69 | publish("sound/button"); 70 | slideshow.next(); 71 | }; 72 | _stopPropButton(skippy); 73 | 74 | // Introduction 75 | slideshow.next(); 76 | 77 | }); -------------------------------------------------------------------------------- /js/lib/Mouse.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////// 2 | // MOUSE //////////////////// 3 | ///////////////////////////// 4 | 5 | var Mouse = { 6 | x:0, y:0, 7 | pressed:false 8 | }; 9 | Mouse.ondown = function(event){ 10 | Mouse.pressed = true; 11 | Mouse.onmove(event); 12 | publish("mouse/down"); 13 | }; 14 | Mouse.onmove = function(event){ 15 | Mouse.x = event.clientX; 16 | Mouse.y = event.clientY; 17 | publish("mouse/move"); 18 | }; 19 | Mouse.onup = function(event){ 20 | Mouse.pressed = false; 21 | publish("mouse/up"); 22 | }; 23 | Mouse.update = function(){ 24 | 25 | // Just pressed, or just released (one frame ago) 26 | Mouse.justPressed = (!Mouse.lastPressed && Mouse.pressed); 27 | Mouse.justReleased = (Mouse.lastPressed && !Mouse.pressed); 28 | 29 | // The last frame's stuff 30 | Mouse.lastX = Mouse.x; 31 | Mouse.lastY = Mouse.y; 32 | Mouse.lastPressed = Mouse.pressed; 33 | 34 | }; 35 | // TOUCH. 36 | function _touchWrapper(callback){ 37 | return function(event){ 38 | var _event = {}; 39 | _event.clientX = event.changedTouches[0].clientX; 40 | _event.clientY = event.changedTouches[0].clientY; 41 | //event.preventDefault(); 42 | callback(_event); 43 | }; 44 | } 45 | 46 | // ALSO DON'T SCROLL WHEN TOUCH 47 | document.body.addEventListener("touchstart", function(e){ 48 | e.preventDefault(); 49 | },false); // do NOT capture. 50 | document.body.addEventListener("touchmove", function(e){ 51 | e.preventDefault(); 52 | },false); // do NOT capture. 53 | 54 | // INIT 55 | Mouse.init = function(target){ 56 | 57 | // Regular mouse 58 | target.addEventListener("mousedown", Mouse.ondown); 59 | target.addEventListener("mousemove", Mouse.onmove); 60 | window.addEventListener("mouseup", Mouse.onup); 61 | 62 | // Touch events 63 | target.addEventListener("touchstart", _touchWrapper(Mouse.ondown), false); 64 | target.addEventListener("touchmove", _touchWrapper(Mouse.onmove), false); 65 | document.body.addEventListener("touchend", function(){ 66 | Mouse.onup(); 67 | }, false); 68 | 69 | }; -------------------------------------------------------------------------------- /js/chapters/H_Conclusion.js: -------------------------------------------------------------------------------- 1 | // 0 - INTRODUCTION 2 | SLIDES.push( 3 | 4 | { 5 | chapter: "Conclusion", 6 | clear:true, 7 | 8 | add:[ 9 | 10 | // Sim 11 | { 12 | type:"sim", 13 | x:0, y:0, 14 | fullscreen: true, 15 | network: { 16 | "contagion":0, 17 | "peeps":[[50,175,1],[194,187,0],[129,261,0],[46,303,0],[68,381,0],[151,408,0],[195,329,0]], 18 | "connections":[[6,2,0],[2,3,0],[3,4,0],[4,5,0],[5,6,0],[6,3,0],[3,5,0],[5,2,0],[2,4,0],[4,6,0],[1,0,0]] 19 | }, 20 | options:{ 21 | infectedFrame: 3, 22 | scale: 1, 23 | _wisdom: true 24 | } 25 | }, 26 | 27 | // Words 28 | /*{ 29 | type:"box", 30 | img:"sprites/conclusion.png", x:-10, y:-15, w:470, h:562 31 | },*/ 32 | { 33 | type:"box", 34 | id:"conclusion_1", 35 | text:"conclusion_1", x:0, y:0, w:960, h:540 36 | } 37 | 38 | ] 39 | 40 | }, 41 | 42 | { 43 | chapter: "Conclusion-Splash", 44 | clear:true, 45 | 46 | add:[ 47 | 48 | // Splash 49 | { 50 | type:"sim", 51 | x:960/2, y:540/2, 52 | fullscreen: true, 53 | network: SPLASH_NETWORK, 54 | options:{ 55 | splash: true, 56 | randomStart: 20 57 | } 58 | }, 59 | 60 | // Words 61 | { 62 | type:"box", 63 | id:"conclusion_2", 64 | text:"conclusion_2", x:180, y:0, w:600, h:540, align:"center" 65 | }, 66 | 67 | ] 68 | 69 | }, 70 | 71 | { 72 | 73 | remove:[ 74 | {type:"box", id:"conclusion_2"} 75 | ], 76 | add:[ 77 | { 78 | type:"box", 79 | id:"conclusion_3", 80 | text:"conclusion_3", x:210, y:160, w:540, h:220, align:"center" 81 | } 82 | ] 83 | 84 | }, 85 | 86 | { 87 | remove:[ 88 | {type:"box", id:"conclusion_3"} 89 | ], 90 | onstart: function(slideshow, state){ 91 | 92 | // SOUND 93 | SOUNDS.chimes.play(); 94 | 95 | // splash animation, then auto-next to CREDITS. 96 | var splash = slideshow.simulations.sims[0]; 97 | splash.options.CONCLUSION = true; 98 | splash.options.CONCLUSION_GLOW_RADIUS = 0; 99 | setTimeout(function(){ 100 | slideshow.next(); 101 | },7000); 102 | 103 | }, 104 | onupdate: function(slideshow, state){ 105 | var splash = slideshow.simulations.sims[0]; 106 | splash.options.CONCLUSION_GLOW_RADIUS += 3; 107 | } 108 | } 109 | 110 | ); -------------------------------------------------------------------------------- /js/slideshow/Pencil.js: -------------------------------------------------------------------------------- 1 | /****************************************** 2 | 3 | THE PENCIL 4 | it's purely visual. replace the cursor 5 | draw / erase / click 6 | 7 | ******************************************/ 8 | 9 | function Pencil(){ 10 | 11 | var self = this; 12 | self.canvas = createCanvas( $("#pencil"), 100, 100 ); 13 | self.ctx = self.canvas.getContext('2d'); 14 | 15 | // Sprites 16 | self.sprite = new Sprite({ 17 | img: "pencil", 18 | frames:3, sw:200, sh:200, 19 | }); 20 | self.toolsSprite = new Sprite({ 21 | img: "sandbox_tools", 22 | frames:6, sw:200, sh:200, 23 | }); 24 | self.sprite.pivotX = self.toolsSprite.pivotX = 0; 25 | self.sprite.pivotY = self.toolsSprite.pivotY = 200; 26 | self.sprite.scale = self.toolsSprite.scale = 0.75; 27 | 28 | var _size = 100; 29 | var _margin = 10; 30 | var _offset = 10; 31 | self.colors = [ 32 | "#888", 33 | "#000", 34 | "#ff5555" 35 | ]; 36 | 37 | // Go to frame? 38 | self.gotoFrame = function(frame){ 39 | self.sprite.gotoFrame(frame); 40 | }; 41 | 42 | // Update 43 | self.update = function(){ 44 | 45 | // Pencil's rotation 46 | if(isNaN(self.x)) self.x=0; 47 | if(isNaN(self.y)) self.y=0; 48 | var xy_velocity = ((Mouse.x-self.x) + (Mouse.y-self.y))/10; // in down-right direction 49 | var gotoRotation = -sigmoid(xy_velocity) * Math.TAU/8; 50 | self.sprite.rotation = self.sprite.rotation*0.8 + gotoRotation*0.2; 51 | self.toolsSprite.rotation = self.sprite.rotation; 52 | 53 | // Pencil's offset 54 | var gotoOffset = Mouse.pressed ? -8 : 10; 55 | _offset = _offset*0.5 + gotoOffset*0.5; 56 | 57 | // Update position 58 | self.x = Mouse.x; 59 | self.y = Mouse.y; 60 | 61 | }; 62 | 63 | // Draw 64 | self.draw = function(){ 65 | 66 | // Move DOM there 67 | self.canvas.style.left = (self.x-_margin) + "px"; 68 | self.canvas.style.top = (self.y-_size+_margin) + "px"; 69 | 70 | // Which sprite? (normal by default...) 71 | var sprite = self.sprite; 72 | var sim = slideshow.simulations.sims[0]; 73 | if(sim){ 74 | var frame = sim.connectorCutter.sandbox_state; 75 | if(frame!=0){ 76 | sprite = self.toolsSprite; 77 | sprite.gotoFrame(frame); 78 | } 79 | } 80 | 81 | // Reset canvas 82 | var ctx = self.ctx; 83 | ctx.clearRect(0,0,self.canvas.width,self.canvas.height); 84 | ctx.save(); 85 | ctx.translate(_margin*2, 200-_margin*2); 86 | 87 | // Draw pencil's dot 88 | if(!Mouse.pressed){ 89 | ctx.save(); 90 | ctx.fillStyle = self.colors[self.sprite.currentFrame]; 91 | ctx.beginPath(); 92 | ctx.globalAlpha = 0.5; 93 | ctx.arc(0, 0, 5, 0, Math.TAU); 94 | ctx.fill(); 95 | ctx.restore(); 96 | } 97 | 98 | // Draw pencil 99 | sprite.x = _offset; 100 | sprite.y = -_offset; 101 | sprite.draw(ctx); 102 | 103 | ctx.restore(); 104 | 105 | }; 106 | 107 | } -------------------------------------------------------------------------------- /js/chapters/A_Preloader.js: -------------------------------------------------------------------------------- 1 | // FOR REUSE: 2 | var SPLASH_NETWORK = { 3 | "contagion":0, 4 | "peeps":[[-408,-115,0],[290,-143,0],[400,-221,0],[-221,373,0],[-214,-378,0],[358,357,0],[-86,-420,0],[269,-369,0],[6,-324,0],[124,299,0],[-550,-119,0],[469,137,0],[366,80,0],[176,381,0],[-452,-217,0],[43,597,0],[238,276,0],[300,120,0],[22,416,0],[373,226,0],[-275,-172,0],[-113,-303,0],[-117,419,0],[-324,5,0],[156,-375,0],[-580,-250,0],[416,-111,0],[-215,-243,0],[-316,-65,0],[33,322,0],[112,456,0],[363,487,0],[-455,13,0],[95,-310,0],[302,-268,0],[507,-313,0],[254,200,0],[207,-249,0],[-177,271,0],[-77,315,0],[-357,387,0],[-462,305,0],[-332,261,0],[-258,195,0],[-556,184,0],[-312,87,0],[600,19,0],[593,158,0],[562,-188,0],[-249,534,0],[-318,-295,0],[-592,55,0],[-99,-541,0],[528,282,0],[322,-31,0],[241,542,0],[-244,-540,0],[-356,-469,0],[-435,-359,0],[456,-11,0],[-382,507,0],[22,-475,0],[14,-611,0],[-89,571,0],[396,-446,0],[284,-521,0],[152,-537,0],[-399,172,0]], 5 | "connections":[[24,37,0],[37,1,0],[1,2,0],[26,1,0],[34,1,0],[13,9,0],[9,30,0],[30,29,0],[29,9,0],[9,18,0],[18,29,0],[18,30,0],[30,13,0],[13,29,0],[18,13,0],[36,19,0],[19,5,0],[19,12,0],[19,16,0],[17,19,0],[11,19,0],[14,25,0],[10,25,0],[10,14,0],[28,20,0],[20,0,0],[0,32,0],[8,21,0],[6,8,0],[21,27,0],[4,21,0],[4,27,0],[21,6,0],[39,3,0],[3,38,0],[38,22,0],[22,39,0],[39,38,0],[22,3,0],[6,4,0],[23,32,0],[42,40,0],[40,41,0],[41,42,0],[37,7,0],[37,33,0],[45,43,0],[47,46,0],[55,31,0],[57,56,0],[58,50,0],[59,54,0],[60,49,0],[62,52,0],[62,61,0],[63,15,0],[64,65,0],[65,66,0],[44,51,0],[48,35,0],[67,43,0],[67,45,0],[61,52,0],[23,0,0],[28,0,0],[53,47,0]] 6 | }; 7 | 8 | SLIDES.push( 9 | 10 | { 11 | chapter: "Preloader", 12 | 13 | add:[ 14 | 15 | // Splash 16 | { 17 | type:"sim", 18 | x:960/2, y:540/2, 19 | fullscreen: true, 20 | network: SPLASH_NETWORK, 21 | options:{ 22 | splash: true, 23 | randomStart: 20 24 | } 25 | }, 26 | 27 | // Words 28 | { 29 | type:"box", 30 | id:"title", 31 | text:"preloader_title", x:180, y:125, w:600, h:230, align:"center" 32 | }, 33 | { 34 | type:"box", 35 | id:"button", 36 | text:"preloader_button", x:180, y:355, w:600, h:100, align:"center" 37 | } 38 | 39 | ], 40 | 41 | onstart: function(slideshow){ 42 | 43 | var button = slideshow.boxes.boxes[1].children[0]; 44 | button.setAttribute("disabled", true); 45 | 46 | // START, FOR REAL 47 | button.onclick = function(){ 48 | publish("START"); 49 | publish("sound/button"); 50 | }; 51 | 52 | }, 53 | 54 | onupdate: function(slideshow, state){ 55 | 56 | // Only once 57 | if(state.FULLY_LOADED) return; 58 | 59 | // Set label 60 | var label; 61 | var button = slideshow.boxes.boxes[1].children[0]; 62 | if(window.PRELOAD_PROGRESS==1){ 63 | state.FULLY_LOADED = true; 64 | label = getWords("preloader_play"); 65 | button.removeAttribute("disabled"); 66 | }else{ 67 | label = getWords("preloader_loading") + " "; 68 | label += Math.round(window.PRELOAD_PROGRESS*100) + "%"; 69 | } 70 | button.innerHTML = label; 71 | 72 | } 73 | 74 | } 75 | 76 | ); -------------------------------------------------------------------------------- /js/chapters/G_Small_World.js: -------------------------------------------------------------------------------- 1 | SLIDES.push( 2 | 3 | { 4 | chapter: "SmallWorld", 5 | clear:true, 6 | 7 | add:[ 8 | 9 | // Sim 10 | // use a DRAWING to impose SOFT CONSTRAINTS 11 | { 12 | type:"sim", 13 | x:150, y:0, 14 | fullscreen: true, 15 | network: { 16 | "contagion":0.25, 17 | "peeps":[[485,50,1],[581,97,0],[389,101,0],[579,200,0],[399,193,0],[487,243,0],[290,312,0],[201,358,0],[196,446,0],[278,509,0],[381,374,0],[367,469,0],[596,370,0],[680,315,0],[778,354,0],[784,454,0],[700,506,0],[604,459,0]], 18 | "connections":[[13,12,0],[12,17,0],[17,16,0],[16,15,0],[15,14,0],[14,13,0],[12,14,0],[14,17,0],[17,13,0],[13,15,0],[15,12,0],[12,16,0],[16,14,0],[13,16,0],[15,17,0],[7,6,0],[6,10,0],[10,11,0],[11,9,0],[9,8,0],[8,7,0],[7,10,0],[10,9,0],[9,7,0],[6,9,0],[8,11,0],[11,6,0],[6,8,0],[7,11,0],[10,8,0]] 19 | }, 20 | options:{ 21 | infectedFrame: 3, 22 | scale: 1, 23 | startUncuttable: true, 24 | _wisdom: true 25 | } 26 | }, 27 | 28 | // UI for the simulation 29 | { 30 | type:"box", 31 | id:"ui", 32 | x:70, y:180, 33 | sim_ui:"blue" 34 | }, 35 | 36 | 37 | // Words 38 | { 39 | type:"box", 40 | text:"bb_1", 41 | x:0, y:10, w:350, h:170 42 | }, 43 | 44 | // Words 45 | { 46 | id:"end", 47 | type:"box", 48 | text:"bb_2", 49 | x:0, y:270, w:300, h:230, 50 | hidden: true 51 | } 52 | 53 | ], 54 | 55 | onupdate:function(slideshow, state){ 56 | 57 | // If ALL infected... 58 | var sim = slideshow.simulations.sims[0]; 59 | var peepCount = 0; 60 | sim.peeps.forEach(function(peep){ 61 | if(peep.infected) peepCount++; 62 | }); 63 | 64 | // Win 65 | if(!state.ended){ 66 | if(peepCount==sim.peeps.length){ 67 | var boxes = slideshow.boxes; 68 | boxes.showChildByID("end", true); 69 | state.ended = true; 70 | sim.win(); 71 | } 72 | } 73 | 74 | } 75 | 76 | }, 77 | 78 | { 79 | chapter: "SmallWorld-Explanation", 80 | clear:true, 81 | add:[ 82 | 83 | // PIC 84 | { 85 | type:"box", 86 | img:"sprites/small_world.png", x:-10, y:95, w:970, h:284 87 | }, 88 | 89 | // Words 90 | { 91 | type:"box", 92 | text:"bb_small_world_1", x:0, y:0, w:960, h:120, 93 | }, 94 | { 95 | type:"box", 96 | text:"bb_small_world_2", x:0, y:120, w:320, h:50, 97 | fontSize:"19px", lineHeight:"21px", 98 | align:"center" 99 | }, 100 | { 101 | type:"box", 102 | text:"bb_small_world_3", x:320, y:120, w:320, h:50, 103 | fontSize:"19px", lineHeight:"21px", 104 | align:"center" 105 | }, 106 | { 107 | type:"box", 108 | text:"bb_small_world_4", x:640, y:130, w:320, h:40, 109 | fontSize:"30px", lineHeight:"30px", 110 | align:"center" 111 | }, 112 | { 113 | type:"box", 114 | text:"bb_small_world_5", x:0, y:360, w:640, h:180, 115 | }, 116 | { 117 | type:"box", 118 | text:"bb_small_world_end", x:640, y:440, w:320, h:100, 119 | align:"center" 120 | } 121 | 122 | ] 123 | } 124 | 125 | ); -------------------------------------------------------------------------------- /js/lib/minpubsub.src.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * MinPubSub 3 | * Copyright(c) 2011 Daniel Lamb 4 | * MIT Licensed 5 | */ 6 | window.c_ = {}; // NICKY - UNIT TESTING 7 | (function (context) { 8 | var MinPubSub = {}; 9 | 10 | // the topic/subscription hash 11 | var cache = context.c_ || {}; //check for 'c_' cache for unit testing 12 | 13 | MinPubSub.publish = function ( /* String */ topic, /* Array? */ args) { 14 | // summary: 15 | // Publish some data on a named topic. 16 | // topic: String 17 | // The channel to publish on 18 | // args: Array? 19 | // The data to publish. Each array item is converted into an ordered 20 | // arguments on the subscribed functions. 21 | // 22 | // example: 23 | // Publish stuff on '/some/topic'. Anything subscribed will be called 24 | // with a function signature like: function(a,b,c){ ... } 25 | // 26 | // publish('/some/topic', ['a','b','c']); 27 | 28 | var subs = cache[topic], 29 | len = subs ? subs.length : 0; 30 | 31 | //can change loop or reverse array if the order matters 32 | while (len--) { 33 | subs[len].apply(context, args || []); 34 | } 35 | }; 36 | 37 | MinPubSub.subscribe = function ( /* String */ topic, /* Function */ callback) { 38 | // summary: 39 | // Register a callback on a named topic. 40 | // topic: String 41 | // The channel to subscribe to 42 | // callback: Function 43 | // The handler event. Anytime something is publish'ed on a 44 | // subscribed channel, the callback will be called with the 45 | // published array as ordered arguments. 46 | // 47 | // returns: Array 48 | // A handle which can be used to unsubscribe this particular subscription. 49 | // 50 | // example: 51 | // subscribe('/some/topic', function(a, b, c){ /* handle data */ }); 52 | 53 | if (!cache[topic]) { 54 | cache[topic] = []; 55 | } 56 | cache[topic].push(callback); 57 | return [topic, callback]; // Array 58 | }; 59 | 60 | MinPubSub.unsubscribe = function ( /* Array */ handle, /* Function? */ callback) { 61 | // summary: 62 | // Disconnect a subscribed function for a topic. 63 | // handle: Array 64 | // The return value from a subscribe call. 65 | // example: 66 | // var handle = subscribe('/some/topic', function(){}); 67 | // unsubscribe(handle); 68 | 69 | var subs = cache[callback ? handle : handle[0]], 70 | callback = callback || handle[1], 71 | len = subs ? subs.length : 0; 72 | 73 | while (len--) { 74 | if (subs[len] === callback) { 75 | subs.splice(len, 1); 76 | } 77 | } 78 | }; 79 | 80 | // UMD definition to allow for CommonJS, AMD and legacy window 81 | if (typeof module === 'object' && module.exports) { 82 | // CommonJS, just export 83 | module.exports = exports = MinPubSub; 84 | } else if (typeof define === 'function' && define.amd) { 85 | // AMD support 86 | define(function () { 87 | return MinPubSub; 88 | }); 89 | } else if (typeof context === 'object') { 90 | // If no AMD and we are in the browser, attach to window 91 | context.publish = MinPubSub.publish; 92 | context.subscribe = MinPubSub.subscribe; 93 | context.unsubscribe = MinPubSub.unsubscribe; 94 | } 95 | 96 | })(this.window); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | !["The Wisdom and/or Madness of Crowds"](http://ncase.me/crowds/social/thumb.png) 2 | 3 | # PLAY IT HERE: [http://ncase.me/crowds/](http://ncase.me/crowds/) 4 | 5 | *The Wisdom and/or Madness of Crowds* is dedicated to the public domain, 6 | and was possible thanks to these open source/Creative Commons resources: 7 | 8 | **Music:** ["Friends 2018" and "Friends 2068"](http://freemusicarchive.org/music/Komiku/Tale_on_the_Late/) by Komiku (CC Zero) 9 | 10 | **Free Sound Effects:** 11 | 12 | * [Pencil Scratching](https://freesound.org/people/JasonElrod/sounds/85485/) by JasonElrod (CC BY) 13 | * [Long Confetti](https://freesound.org/people/dmjames/sounds/140095/) by dmjames (CC Zero) 14 | * [Short Confetti](https://freesound.org/people/beerre/sounds/344965/) by beerre (CC Zero) 15 | * [Various button sounds](https://freesound.org/people/Owdeo/sounds/116653/) by Owdeo (CC BY-NC) 16 | * [Contagion spreading](https://freesound.org/people/UnderlinedDesigns/sounds/191766/) by UnderlinedDesigns (CC Zero) 17 | * [Cut connection](https://freesound.org/people/megashroom/sounds/390167/) by megashroom (CC Zero) 18 | * [Can't cut connection](https://freesound.org/people/johnnypanic/sounds/36280/) by johnnypanic (CC BY) 19 | * [Ending Windchimes](https://freesound.org/people/InspectorJ/sounds/353194/) by InspectorJ (CC BY) 20 | * [Sandbox: Add Peep](https://freesound.org/people/greenvwbeetle/sounds/244654/) by greenvwbeetle (CC Zero) 21 | * [Sandbox: Move Peep](https://freesound.org/people/ermfilm/sounds/130013/) by ermfilm (CC BY) 22 | * [Sandbox: Delete Peep](https://freesound.org/people/Bash360/sounds/214854/) by Bash360 (CC Zero) 23 | * [Sandbox: Clear All](https://freesound.org/people/dogfishkid/sounds/399303/) by dogfishkid (CC BY) 24 | 25 | **Open Source Libraries:** 26 | 27 | * [Howler.js](https://howlerjs.com/) for the audio 28 | * [MinPubSub](https://github.com/daniellmb/MinPubSub) for publish/subscribe 29 | 30 | **Font:** [Patrick Hand](https://fonts.google.com/specimen/Patrick+Hand) by Patrick Wagesreiter 31 | 32 | # HOW TO TRANSLATE THIS THING 33 | 34 | **[IMPORTANT: 35 | BEFORE YOU MAKE A TRANSLATION, CHECK THE "ISSUES" TAB ABOVE, 36 | TO SEE IF SOMEONE ELSE IS ALREADY WORKING ON IT. 37 | If so, maybe you can collaborate! 38 | And if no one else is, PLEASE CREATE A NEW ISSUE in this repo 39 | so that others know you're working on it!]** 40 | 41 | Translations done so far: (none) 42 | 43 | **Step 1)** Clone this repo! 44 | 45 | **Step 2)** Look up the two-letter code of the language you're translating to here: 46 | [https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) 47 | 48 | **Step 3)** *COPY* `index.html`, and name the copy [your-two-letter-code].html. 49 | For example: `de.html`, `ar.html`, `zh.html`, etc... 50 | 51 | **Step 4)** Translate *THAT* page (it's about 3600+ words). Do NOT modify the original `index.html`! 52 | Also, please feel free to credit yourself as a translator :) 53 | 54 | **Step 5)** Add one line to the end of `translations.txt` so that the game "knows" your translation exists. 55 | (more specific instructions will be inside that file) 56 | 57 | **Step 6)** Send a Pull Request so I can make your translation go live! 58 | 59 | **Step 7)** 🎉 fweeeee 60 | 61 | # PUBLIC DOMAIN "LICENSE" 62 | 63 | [Creative Commons Zero](https://github.com/ncase/trust/blob/gh-pages/LICENSE): it's a public domain dedication, so basically, do whatever you want! Attribution is super appreciated, but I'm not gonna send legal goons after you or anything. -------------------------------------------------------------------------------- /js/slideshow/Navigation.js: -------------------------------------------------------------------------------- 1 | /************************* 2 | 3 | Giant "everything" class that handles all the misc UI: 4 | navigation, modal dialogues, audio, etc 5 | 6 | *************************/ 7 | function Navigation(){ 8 | 9 | var self = this; 10 | 11 | // Navigation buttons 12 | var nav_buttons = $all("#navigation > div"); 13 | nav_buttons.forEach(function(nav){ 14 | 15 | // Show label bubble 16 | (function(nav){ 17 | nav.onmouseover = function(){ 18 | _showBubble(nav); 19 | }; 20 | nav.onmouseout = function(){ 21 | _hideBubble(); 22 | }; 23 | })(nav); 24 | 25 | // If it's a chapter, when you click it, go to that chapter! 26 | var chapter = nav.getAttribute("chapter"); 27 | if(chapter){ 28 | (function(nav, chapter){ 29 | nav.onclick = function(){ 30 | publish("sound/button"); 31 | slideshow.gotoChapter(chapter); 32 | }; 33 | _stopPropButton(nav); 34 | })(nav, chapter); 35 | } 36 | 37 | // If it's a modal... 38 | var modal = nav.getAttribute("modal"); 39 | if(modal){ 40 | (function(nav, modal){ 41 | nav.onclick = function(){ 42 | publish("sound/button"); 43 | publish("modal/"+modal); 44 | }; 45 | _stopPropButton(nav); 46 | })(nav, modal); 47 | } 48 | 49 | }); 50 | subscribe("slideshow/goto/",function(chapterID){ 51 | 52 | nav_buttons.forEach(function(nav){ 53 | var chapter = nav.getAttribute("chapter"); 54 | if(chapter==chapterID){ 55 | nav.setAttribute("highlight", true); 56 | }else{ 57 | nav.removeAttribute("highlight"); 58 | } 59 | }); 60 | 61 | }); 62 | 63 | // Navigation label bubble 64 | var bubble = $("#nav_bubble"); 65 | var isShowingBubble = false; 66 | var _showBubble = function(nav){ 67 | 68 | var offset = _getBoundingClientRect(nav).x - _getBoundingClientRect($("#navigation")).x; 69 | var label = nav.children[1].innerHTML; 70 | bubble.style.left = ( offset - (220/2) + (36/2) ) + "px"; 71 | bubble.innerHTML = label; 72 | 73 | bubble.style.display = "block"; 74 | setTimeout(function(){ 75 | bubble.style.opacity = 1; 76 | bubble.style.top = (-85) + "px"; 77 | },1); 78 | isShowingBubble = true; 79 | 80 | }; 81 | var _hideBubble = function(){ 82 | isShowingBubble = false; 83 | bubble.style.opacity = 0; 84 | bubble.style.top = (-80) + "px"; 85 | }; 86 | var _countdown = 0; 87 | subscribe("update", function(){ 88 | if(isShowingBubble){ 89 | _countdown = 0.25; 90 | }else{ 91 | if(_countdown>0){ 92 | _countdown -= 1/60; 93 | }else{ 94 | bubble.style.display = "none"; 95 | } 96 | } 97 | }); 98 | 99 | // Sound 100 | var isMute = false; 101 | $("#sound").onclick = function(){ 102 | if(isMute){ 103 | Howler.mute(isMute = false); 104 | $("#sound").setAttribute("mute","no"); 105 | }else{ 106 | Howler.mute(isMute = true); 107 | $("#sound").setAttribute("mute","yes"); 108 | } 109 | }; 110 | _stopPropButton($("#sound")); 111 | 112 | } 113 | 114 | /**************************** 115 | 116 | SOCIAL SHARING 117 | 118 | ****************************/ 119 | 120 | var shareURL = encodeURIComponent( window.location.href ); 121 | var shareTitle = encodeURIComponent( $("#share_title").innerText.trim() ); 122 | var shareDesc = encodeURIComponent( $("#share_desc").innerText.trim() ); 123 | 124 | $("#fb").href = "https://www.facebook.com/sharer/sharer.php?u="+shareURL+"&t="+shareDesc+" "+shareURL; 125 | $("#tw").href = "https://twitter.com/intent/tweet?source="+shareURL+"&text="+shareDesc+" "+shareURL; 126 | $("#em").href = "mailto:?subject="+shareTitle+"&body="+shareDesc+" "+shareURL; 127 | -------------------------------------------------------------------------------- /js/sim/Connection.js: -------------------------------------------------------------------------------- 1 | function Connection(config){ 2 | 3 | var self = this; 4 | 5 | // Properties 6 | self.from = config.from; 7 | self.to = config.to; 8 | self.uncuttable = config.uncuttable || false; 9 | self.sim = config.sim; 10 | 11 | // Line Sprite 12 | self.sprite = new Sprite({ 13 | img: "line", 14 | frames:1, sw:300, sh:20, 15 | }); 16 | self.sprite.pivotX = 2.8; 17 | self.sprite.pivotY = 10; 18 | 19 | // Dot Sprite 20 | self.dotSprite = new Sprite({ 21 | img: "peeps", 22 | frames:6, sw:200, sh:200, 23 | }); 24 | self.dotSprite.pivotX = 100; 25 | self.dotSprite.pivotY = 100; 26 | self.dotSprite.scale = 0.1; 27 | 28 | // Update 29 | self.update = function(){}; 30 | 31 | // Draw 32 | self.draw = function(ctx){ 33 | 34 | var s = self.sim.options.scale || 1; 35 | 36 | ctx.save(); 37 | ctx.translate(self.from.x, self.from.y); 38 | var dx = self.to.x - self.from.x; 39 | var dy = self.to.y - self.from.y; 40 | var a = Math.atan2(dy,dx); 41 | var dist = Math.sqrt(dx*dx + dy*dy); 42 | ctx.rotate(a); 43 | 44 | // SHAKE 45 | if(self.shaking>=0 && self.shaking<1){ 46 | self.shaking+=0.05; 47 | var amplitude = (1-self.shaking)*3; 48 | ctx.translate(0, Math.sin(self.shaking*Math.TAU*3)*amplitude); 49 | } 50 | 51 | self.sprite.scaleX = dist/300; 52 | self.sprite.scaleY = self.uncuttable ? 1 : 0.5; // thick=uncuttable 53 | //self.sprite.scaleY *= s; 54 | //self.sprite.rotation = a; 55 | self.sprite.draw(ctx); 56 | ctx.restore(); 57 | 58 | // DRAW CONTAGION DOT 59 | if(self.contagionDot){ 60 | var infectedFrame = self.sim.options.infectedFrame || 1; 61 | self.dotSprite.x = self.contagionDot.x; 62 | self.dotSprite.y = self.contagionDot.y; 63 | self.dotSprite.gotoFrame(infectedFrame); 64 | self.dotSprite.draw(ctx); 65 | } 66 | 67 | }; 68 | 69 | // Hit Test with a LINE SEGMENT 70 | // code adapted from https://gist.github.com/Joncom/e8e8d18ebe7fe55c3894 71 | self.hitTest = function(line){ 72 | 73 | var p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y; 74 | p0_x = line[0]; 75 | p0_y = line[1]; 76 | p1_x = line[2]; 77 | p1_y = line[3]; 78 | p2_x = self.from.x; 79 | p2_y = self.from.y; 80 | p3_x = self.to.x; 81 | p3_y = self.to.y; 82 | 83 | var s1_x, s1_y, s2_x, s2_y; 84 | s1_x = p1_x - p0_x; 85 | s1_y = p1_y - p0_y; 86 | s2_x = p3_x - p2_x; 87 | s2_y = p3_y - p2_y; 88 | var s, t; 89 | s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y); 90 | t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); 91 | 92 | return (s >= 0 && s <= 1 && t >= 0 && t <= 1); 93 | 94 | }; 95 | 96 | // Animate 97 | self.contagionDot = null; 98 | self.animate = function(){ 99 | 100 | // Infection? 101 | var cFrom, cTo; 102 | if(self.from.infected && (!self.to.infected && self.to.isPastThreshold)){ 103 | cFrom = self.from; 104 | cTo = self.to; 105 | } 106 | if(self.to.infected && (!self.from.infected && self.from.isPastThreshold)){ 107 | cFrom = self.to; 108 | cTo = self.from; 109 | } 110 | 111 | // boop! 112 | if(cFrom && cTo){ 113 | 114 | // ANIMATE IT 115 | cFrom = { x:cFrom.x, y:cFrom.y }; 116 | cTo = { x:cTo.x, y:cTo.y }; 117 | tweenPosition(cFrom, cTo, function(point){ 118 | self.contagionDot = point; 119 | }, easeLinear); 120 | 121 | // Then, goodbye later 122 | setTimeout(function(){ 123 | self.contagionDot = null; 124 | },333); 125 | 126 | } 127 | 128 | }; 129 | self.shaking = -1; 130 | self.shake = function(){ 131 | self.shaking = 0; 132 | }; 133 | 134 | } -------------------------------------------------------------------------------- /js/slideshow/Modal.js: -------------------------------------------------------------------------------- 1 | 2 | // SHOW BONUS BOXES 3 | subscribe("bonus/show", function(bonus_id){ 4 | 5 | publish("sound/button"); 6 | 7 | var words = document.querySelector("bonus#"+bonus_id).innerHTML.trim(); 8 | $("#modal_content").innerHTML = words; 9 | Modal.show(true); // show large for bonus 10 | }); 11 | 12 | // SHOW REFERENCES 13 | //var SHOWING_SUPPORTERS = false; 14 | subscribe("reference/show", function(ref_id){ 15 | 16 | publish("sound/button"); 17 | 18 | var footnote = document.querySelector("reference#"+ref_id+" > div").innerHTML.trim(); 19 | $("#modal_content").innerHTML = footnote; 20 | var noteLength = $("#modal_content").innerText.length; // innerTEXT, so no links 21 | 22 | // HACK: IF IT'S PATREON PEOPLE, *NOW* SHOW IFRAME 23 | if(ref_id=="supporters"){ 24 | $("#modal_content").innerHTML = footnote+'

'+ 25 | ''; 26 | } 27 | 28 | if($("reference#"+ref_id).getAttribute("large")){ 29 | Modal.show(true); // force large 30 | }else{ 31 | Modal.show(noteLength>500); // variable length 32 | } 33 | 34 | }); 35 | 36 | // ESCAPE (keyboard shortcut) 37 | subscribe("key/down/escape", function(){ 38 | Modal.hide(); 39 | }); 40 | 41 | window.Modal = { 42 | currentlyShowing: "", 43 | show: function(large){ 44 | $("#modal_container").setAttribute("show","yes"); 45 | $("#modal").setAttribute("size", large ? "large" : "small"); 46 | $("#modal_content_container").scrollTop = 0; // scroll to top 47 | }, 48 | hide: function(){ 49 | Modal.currentlyShowing = ""; 50 | publish("sound/button"); 51 | $("#modal_container").removeAttribute("show"); 52 | }, 53 | showAll: function(thing){ 54 | 55 | // ALL the things, in one go! 56 | var html = ""; 57 | $all(thing).filter(function(thing){ 58 | return !thing.getAttribute("hidden"); // NOT hidden 59 | }).forEach(function(thing){ 60 | html += "
"+thing.innerHTML+"
"; 61 | }); 62 | $("#modal_content").innerHTML = html; 63 | 64 | // Show in large box 65 | Modal.show(true); 66 | 67 | } 68 | }; 69 | 70 | $("#modal_bg").onclick = Modal.hide; 71 | $("#modal_close").onclick = Modal.hide; 72 | _stopPropButton($("#modal_bg")); 73 | _stopPropButton($("#modal_close")); 74 | 75 | // Show big collected modals 76 | subscribe("modal/bonus", function(){ 77 | if(Modal.currentlyShowing == "bonus"){ 78 | Modal.hide(); 79 | }else{ 80 | Modal.currentlyShowing = "bonus"; 81 | Modal.showAll("bonus"); 82 | } 83 | }); 84 | subscribe("modal/references", function(){ 85 | if(Modal.currentlyShowing == "reference"){ 86 | Modal.hide(); 87 | }else{ 88 | Modal.currentlyShowing = "reference"; 89 | Modal.showAll("reference"); 90 | } 91 | }); 92 | 93 | // Translations 94 | subscribe("modal/translations", function(){ 95 | 96 | if(Modal.currentlyShowing == "translations"){ 97 | Modal.hide(); 98 | }else{ 99 | Modal.currentlyShowing = "translations"; 100 | 101 | // Translation HTML 102 | var html = ""; 103 | if(window.TRANSLATIONS.length>0){ 104 | html += getWords("translations_exist"); 105 | }else{ 106 | html += getWords("translations_do_not_exist"); 107 | } 108 | html += " "+getWords("translations_add")+""; 109 | html += "
"; 110 | html += _createLinks(" · "); 111 | $("#modal_content").innerHTML = html; 112 | 113 | // Show in large box 114 | Modal.show(false); 115 | 116 | } 117 | 118 | }); 119 | 120 | // MOBILE URGGHHHH 121 | $("#modal_content_container").ontouchstart = function(event){ 122 | event.stopPropagation(); 123 | }; 124 | $("#modal_content_container").ontouchmove = function(event){ 125 | event.stopPropagation(); 126 | }; 127 | 128 | 129 | -------------------------------------------------------------------------------- /js/slideshow/Preloader.js: -------------------------------------------------------------------------------- 1 | // Load just enough for the splash screen 2 | subscribe("prepreload", function(){ 3 | 4 | Preload([ 5 | 6 | // For the Splash 7 | {id:"button_large", image:"sprites/button_large.png"}, 8 | {id:"line", image:"sprites/line.png"}, 9 | {id:"peeps", image:"sprites/peeps.png"}, 10 | {id:"pencil", image:"sprites/pencil.png"}, 11 | 12 | // Sound Effects 13 | {id:"pencil", audio:"audio/pencil.mp3"}, 14 | {id:"pencil_short", audio:"audio/pencil_short.mp3"}, 15 | {id:"snip0", audio:"audio/snip0.mp3"}, 16 | {id:"snip1", audio:"audio/snip1.mp3"}, 17 | {id:"snip2", audio:"audio/snip2.mp3"}, 18 | 19 | // UI 20 | {id:"sound", image:"sprites/ui/sound.png"}, 21 | {id:"sharing", image:"sprites/ui/sharing.png"}, 22 | 23 | ],function(progress){ 24 | if(progress==1){ 25 | publish("prepreload/done"); 26 | publish("preload"); 27 | } 28 | }); 29 | 30 | }); 31 | 32 | // Load the rest of it 33 | window.PRELOAD_PROGRESS = 0; 34 | subscribe("preload", function(){ 35 | 36 | Preload([ 37 | 38 | // Music 39 | {id:"bg_music", audio:"audio/bg_music.mp3"}, 40 | 41 | // Sound Effects 42 | {id:"bonk", audio:"audio/bonk.mp3"}, 43 | {id:"boom", audio:"audio/boom.mp3"}, 44 | {id:"button0", audio:"audio/button0.mp3"}, 45 | {id:"button1", audio:"audio/button1.mp3"}, 46 | {id:"button2", audio:"audio/button2.mp3"}, 47 | {id:"chimes", audio:"audio/chimes.mp3"}, 48 | {id:"contagion", audio:"audio/contagion.mp3"}, 49 | {id:"party", audio:"audio/party.mp3"}, 50 | {id:"party_short", audio:"audio/party_short.mp3"}, 51 | {id:"pluck0", audio:"audio/pluck0.mp3"}, 52 | {id:"pluck1", audio:"audio/pluck1.mp3"}, 53 | {id:"pluck2", audio:"audio/pluck2.mp3"}, 54 | {id:"pluck3", audio:"audio/pluck3.mp3"}, 55 | {id:"pop", audio:"audio/pop.mp3"}, 56 | {id:"scratch_in", audio:"audio/scratch_in.mp3"}, 57 | {id:"scratch_out", audio:"audio/scratch_out.mp3"}, 58 | {id:"squeak_down", audio:"audio/squeak_down.mp3"}, 59 | {id:"squeak_up", audio:"audio/squeak_up.mp3"}, 60 | {id:"trash", audio:"audio/trash.mp3"}, 61 | 62 | // For the slides 63 | {id:"icons/blue", image:"sprites/icons/blue.png"}, 64 | {id:"icons/gray", image:"sprites/icons/gray.png"}, 65 | {id:"icons/red", image:"sprites/icons/red.png"}, 66 | {id:"icons/yellow", image:"sprites/icons/yellow.png"}, 67 | {id:"confetti", image:"sprites/confetti.png"}, 68 | {id:"nasa", image:"sprites/nasa.png"}, 69 | {id:"red_button", image:"sprites/red_button.png"}, 70 | {id:"sandbox_tools", image:"sprites/sandbox_tools.png"}, 71 | {id:"scratch", image:"sprites/scratch.png"}, 72 | {id:"small_world", image:"sprites/small_world.png"}, 73 | {id:"tutorial_connect", image:"sprites/tutorial_connect.png"}, 74 | {id:"tutorial_disconnect", image:"sprites/tutorial_disconnect.png"}, 75 | 76 | // UI 77 | {id:"arrow", image:"sprites/ui/arrow.png"}, 78 | {id:"bonus", image:"sprites/ui/bonus.png"} 79 | 80 | ],function(progress){ 81 | window.PRELOAD_PROGRESS = progress; 82 | }); 83 | 84 | }); 85 | 86 | 87 | /////////////////////////////////////////// 88 | /////////////////////////////////////////// 89 | 90 | var IMAGES = {}; // todo: actually USE these images 91 | var SOUNDS = {}; 92 | function Preload(assets, onProgress){ 93 | 94 | var loaded = 0; 95 | var _onAssetLoad = function(){ 96 | loaded++; 97 | onProgress(loaded/assets.length); 98 | }; 99 | 100 | assets.forEach(function(asset){ 101 | 102 | // Image 103 | if(asset.image){ 104 | var img = new Image(); 105 | img.onload = _onAssetLoad; 106 | img.src = asset.image; 107 | IMAGES[asset.id] = img; 108 | } 109 | 110 | // Audio 111 | if(asset.audio){ 112 | var sound = new Howl({ src:[asset.audio] }); 113 | sound.once('load', _onAssetLoad); 114 | SOUNDS[asset.id] = sound; 115 | } 116 | 117 | }); 118 | 119 | } 120 | 121 | 122 | -------------------------------------------------------------------------------- /js/chapters/F_Bonding_And_Bridging.js: -------------------------------------------------------------------------------- 1 | SLIDES.push( 2 | 3 | { 4 | chapter: "BB", 5 | clear:true, 6 | 7 | add:[ 8 | 9 | // Sim 10 | // DRAWING FOR SOFT CONSTRAINTS... 11 | { 12 | type:"sim", 13 | x:0, y:130, 14 | fullscreen: true, 15 | network: { 16 | "contagion":0.25, 17 | "peeps":[ 18 | [90,-67,1],[181,-71,0],[36,21,0],[107,98,0],[206,92,0],[244,6,0], 19 | [416,106,1],[352,181,0],[415,267,0],[528,268,0],[595,186,0],[532,107,0], 20 | [769,-68,1],[701,6,0],[753,96,0],[855,110,0],[928,35,0],[867,-59,0] 21 | ], 22 | "connections":[[13,12,0],[12,17,0],[16,15,0],[14,13,0],[13,16,0],[14,17,0],[17,15,0],[15,12,0],[12,16,0],[15,13,0],[17,16,0],[14,12,0],[13,17,0],[0,1,0],[2,5,0],[4,3,0],[15,14,0],[14,16,0]] 23 | }, 24 | options:{ 25 | infectedFrame: 3, 26 | scale: 1, 27 | _wisdom: true, 28 | NO_BONK: true 29 | } 30 | }, 31 | 32 | // UI for the simulation 33 | { 34 | type:"box", 35 | id:"ui", 36 | x:370, y:445, 37 | sim_ui:"blue" 38 | }, 39 | 40 | // Words 41 | { 42 | type:"box", 43 | text:"bonding_1", 44 | x:230, y:0+15, w:500, h:70, 45 | align:"center" 46 | }, 47 | 48 | // Words 2 49 | { 50 | type:"box", 51 | text:"bonding_2", 52 | x:300, y:70+15, w:360, h:100, 53 | align:"center" 54 | }, 55 | 56 | // Words End 57 | { 58 | id:"end", 59 | type:"box", 60 | text:"bonding_end", 61 | x:660, y:290, w:300, h:250, 62 | hidden:true 63 | } 64 | 65 | ], 66 | 67 | onupdate:function(slideshow, state){ 68 | 69 | // If Peeps[6] to Peep[11] pass.. 70 | var sim = slideshow.simulations.sims[0]; 71 | var peepCount = 0; 72 | for(var i=6; i<=11; i++){ 73 | var peep = sim.peeps[i]; 74 | if(peep.infected) peepCount++; 75 | } 76 | 77 | // Win 78 | if(!state.ended){ 79 | if(peepCount==6){ 80 | var boxes = slideshow.boxes; 81 | boxes.showChildByID("end", true); 82 | state.ended = true; 83 | sim.win({ 84 | x:330+5, y:160-120+5, 85 | width:280, height:280, 86 | small:true 87 | }); 88 | } 89 | } 90 | 91 | } 92 | 93 | }, 94 | 95 | { 96 | chapter: "BB-Bridge", 97 | clear:true, 98 | 99 | add:[ 100 | 101 | // Sim 102 | { 103 | type:"sim", 104 | x:-70, y:-30, 105 | fullscreen: true, 106 | network: { 107 | "contagion":0.25, 108 | "peeps":[[182,92,1],[300,106,0],[107,196,0],[151,300,0],[301,309,0],[354,213,0],[441,384,0],[500,290,0],[644,304,0],[691,422,0],[621,510,0],[491,488,0]], 109 | "connections":[[6,7,1],[7,8,1],[8,9,1],[9,10,1],[10,11,1],[11,6,1],[6,9,1],[9,11,1],[11,8,1],[8,10,1],[10,7,1],[7,9,1],[11,7,1],[6,10,1],[6,8,1],[0,1,1],[1,5,1],[5,4,1],[4,3,1],[2,3,1],[2,0,1],[3,1,1]] 110 | }, 111 | options:{ 112 | infectedFrame: 3, 113 | scale: 1, 114 | startUncuttable: true, 115 | _wisdom: true 116 | } 117 | }, 118 | 119 | // UI for the simulation 120 | { 121 | type:"box", 122 | id:"ui", 123 | x:95, y:390, 124 | sim_ui:"blue" 125 | }, 126 | 127 | // Words 128 | { 129 | type:"box", 130 | text:"bridging_1", 131 | x:340, y:30, w:620, h:120 132 | }, 133 | 134 | // Words End 135 | { 136 | id:"end", 137 | type:"box", 138 | text:"bridging_end", 139 | x:660, y:180, w:300, h:360, 140 | hidden:true 141 | } 142 | 143 | ], 144 | 145 | onupdate:function(slideshow, state){ 146 | 147 | // If ALL infected... 148 | var sim = slideshow.simulations.sims[0]; 149 | var peepCount = 0; 150 | sim.peeps.forEach(function(peep){ 151 | if(peep.infected) peepCount++; 152 | }); 153 | 154 | // Win 155 | if(!state.ended){ 156 | if(peepCount==sim.peeps.length){ 157 | var boxes = slideshow.boxes; 158 | boxes.showChildByID("end", true); 159 | state.ended = true; 160 | sim.win(); 161 | } 162 | } 163 | 164 | } 165 | 166 | } 167 | 168 | ); -------------------------------------------------------------------------------- /js/slideshow/Boxes.js: -------------------------------------------------------------------------------- 1 | /****************************** 2 | 3 | Boxes of HTML. With words and pictures! 4 | 5 | ******************************/ 6 | 7 | function Boxes(){ 8 | 9 | var self = this; 10 | self.dom = $("#slideshow"); 11 | 12 | self.boxes = []; 13 | 14 | // Clear 15 | self.clear = function(){ 16 | self.boxes.forEach(function(box){ 17 | self.dom.removeChild(box); 18 | if(box.kill) box.kill(); 19 | }); 20 | self.boxes = []; 21 | }; 22 | 23 | // Add Box 24 | self.add = function(config, withFade){ 25 | 26 | // Add to DOM 27 | var box = document.createElement("div"); 28 | box.className = "box"; 29 | if(!withFade){ 30 | self.dom.appendChild(box); 31 | }else{ 32 | fadeIn(self.dom, box); 33 | } 34 | 35 | // Standard box properties... 36 | if(config.id) box.id = config.id; 37 | if(config.x) box.style.left = config.x + "px"; 38 | if(config.y) box.style.top = config.y + "px"; 39 | if(config.w) box.style.width = config.w + "px"; 40 | if(config.h) box.style.height = config.h + "px"; 41 | if(config.hidden) box.style.display = "none"; 42 | 43 | // background 44 | if(config.background){ 45 | box.style.left = "-1000px"; 46 | box.style.top = "-1000px"; 47 | box.style.width = 10000 + "px"; 48 | box.style.height = 10000 + "px"; 49 | box.style.background = config.background; 50 | } 51 | 52 | // words: 53 | if(config.text){ 54 | box.innerHTML = getWords(config.text); 55 | if(config.align) box.style.textAlign = config.align; 56 | if(config.color) box.style.color = config.color; 57 | if(config.fontSize) box.style.fontSize = config.fontSize; 58 | if(config.lineHeight) box.style.lineHeight = config.lineHeight; 59 | } 60 | 61 | // pics: 62 | if(config.img){ 63 | box.classList.add("image"); 64 | box.style.backgroundImage = "url("+config.img+")" 65 | } 66 | 67 | // Sim UI 68 | if(config.sim_ui){ 69 | var simUI = new SimUI(box, config.sim_ui); 70 | } 71 | 72 | // Sandbox UI 73 | if(config.sandbox){ 74 | var sandboxUI = new SandboxUI(box); 75 | } 76 | 77 | // Replace "next" buttons! 78 | var next; 79 | if(next = box.querySelector("next")){ 80 | 81 | // Create next button 82 | var nextButton = document.createElement("div"); 83 | nextButton.className = "next_button"; 84 | nextButton.innerHTML = next.innerHTML; 85 | nextButton.onclick = function(){ 86 | publish("sound/button"); 87 | slideshow.next(); 88 | }; 89 | 90 | // to prevent sim from resetting... 91 | _stopPropButton(nextButton); 92 | 93 | // Replace it in parent! 94 | next.parentNode.replaceChild(nextButton, next); 95 | 96 | } 97 | 98 | // Add onclicks to "ref"s! 99 | box.querySelectorAll("ref").forEach(function(ref){ 100 | ref.onclick = function(){ 101 | var id = ref.id; 102 | publish("reference/show",[id]); 103 | }; 104 | _stopPropButton(ref); 105 | }); 106 | 107 | // Bonus boxes... 108 | box.querySelectorAll("bon").forEach(function(bon){ 109 | var title = $("bonus#"+bon.id+" > h3").innerHTML.trim(); 110 | bon.innerHTML = title; 111 | bon.onclick = function(){ 112 | publish("bonus/show", [bon.id]); 113 | }; 114 | _stopPropButton(bon); 115 | }); 116 | 117 | // Replace icons 118 | box.querySelectorAll("icon").forEach(function(icon){ 119 | 120 | // Create next button 121 | var name = icon.getAttribute("name"); 122 | var src = "sprites/icons/"+name+".png"; 123 | var img = new Image(); 124 | img.src = src; 125 | img.className = "peep_icon"; 126 | 127 | // Replace it in parent! 128 | icon.parentNode.replaceChild(img, icon); 129 | 130 | }); 131 | 132 | // Add to array 133 | self.boxes.push(box); 134 | 135 | }; 136 | 137 | // Update & Draw... nothing 138 | self.update = function(){}; 139 | self.draw = function(){}; 140 | 141 | /////////////////////// 142 | // HELPERS AND STUFF // 143 | /////////////////////// 144 | 145 | self.getChildByID = function(id){ 146 | return self.boxes.find(function(box){ 147 | return box.id==id; 148 | }); 149 | }; 150 | self.showChildByID = function(id, withFade){ 151 | var toShow = self.getChildByID(id); 152 | if(!withFade){ 153 | toShow.style.display = "block"; 154 | }else{ 155 | fadeIn(self.dom, toShow); 156 | } 157 | }; 158 | 159 | self.removeChildByID = function(id, withFade){ 160 | 161 | var removeBox = self.getChildByID(id); 162 | if(!withFade){ 163 | self.dom.removeChild(removeBox); 164 | }else{ 165 | fadeOut(self.dom, removeBox); 166 | } 167 | removeFromArray(self.boxes, removeBox); 168 | if(removeBox.kill) removeBox.kill(); 169 | 170 | }; 171 | 172 | } 173 | -------------------------------------------------------------------------------- /js/chapters/D_Simple_Contagion.js: -------------------------------------------------------------------------------- 1 | // 2 - Simple Contagion 2 | 3 | // Puzzles for re-use in Complex Contagion... 4 | var CONTAGION_PUZZLE = { 5 | "peeps":[[53,195,1],[169,297,0],[416,228,0],[323,325,0],[550,234,0],[787,304,0],[627,328,0],[415,419,0],[544,422,0],[906,199,0]], 6 | "connections":[[0,1],[1,3],[3,2],[3,7],[7,8],[8,6],[6,4],[4,2],[6,5],[5,9]] 7 | }; 8 | var CASCADE_PUZZLE = { 9 | "peeps":[[31,201,1],[148,238,0],[267,317,0],[166,392,0],[282,437,0],[481,202,0],[401,284,0],[472,367,0],[590,340,0],[602,236,0],[843,313,0],[719,376,0],[930,413,0],[846,514,0],[728,488,0]], 10 | "connections":[[0,1,1],[3,2,1],[2,4,1],[4,3,1],[6,7,1],[7,8,1],[8,9,1],[9,5,1],[5,6,1],[6,9,1],[9,7,1],[7,5,1],[5,8,1],[8,6,1],[11,10,1],[11,14,1],[14,13,1],[13,12,1],[12,10,1],[11,12,1],[12,14,1],[14,10,1],[10,13,1],[13,11,1]] 11 | } 12 | 13 | SLIDES.push( 14 | { 15 | chapter: "Simple", 16 | clear:true, 17 | 18 | add:[ 19 | 20 | // Intro text 21 | { 22 | type:"box", 23 | id:"simple_simple", 24 | text:"simple_simple", 25 | x:80, y:0, w:800, h:160, 26 | align: "center" 27 | }, 28 | 29 | // Lil' contagion 30 | { 31 | type:"sim", 32 | id:"contagion", 33 | x:0, y:80, 34 | fullscreen: true, 35 | network: { 36 | "contagion":0, 37 | "peeps":CONTAGION_PUZZLE.peeps, 38 | "connections":CONTAGION_PUZZLE.connections 39 | }, 40 | options:{ 41 | infectedFrame: 1, 42 | scale: 1.25, 43 | _dunce: true 44 | } 45 | }, 46 | 47 | // UI for the simulation 48 | { 49 | type:"box", 50 | id:"ui", 51 | x:380, y:165, 52 | sim_ui:"red" 53 | }, 54 | 55 | // Outro text 56 | { 57 | id:"end", 58 | type:"box", 59 | text:"simple_simple_end", 60 | x:660, y:440, w:300, h:100, 61 | hidden:true 62 | } 63 | 64 | ], 65 | 66 | onupdate:function(slideshow, state){ 67 | 68 | // Show end if EVERYONE is infected 69 | if(!state.ended){ 70 | var sim = slideshow.simulations.sims[0]; 71 | var peepCount = 0; 72 | sim.peeps.forEach(function(peep){ 73 | if(peep.infected) peepCount++; 74 | }); 75 | if(peepCount==sim.peeps.length){ 76 | /*var boxes = slideshow.boxes; 77 | boxes.showChildByID("end", true);*/ 78 | state.ended = true; 79 | slideshow.next(); 80 | } 81 | } 82 | 83 | } 84 | 85 | }, 86 | { 87 | remove:[ 88 | {type:"box", id:"simple_simple"} 89 | ], 90 | move:[ 91 | {type:"box", id:"ui", y:5}, 92 | {type:"sim", id:"contagion", y:-80} 93 | ], 94 | add:[ 95 | { 96 | type:"box", 97 | text:"simple_simple_2", 98 | x:0, y:390, w:650, h:100, 99 | align: "right" 100 | }, 101 | { 102 | type:"box", 103 | text:"simple_simple_end", 104 | x:660, y:440, w:300, h:90 105 | } 106 | ] 107 | }, 108 | { 109 | chapter: "Simple-Cascade", 110 | clear:true, 111 | 112 | add:[ 113 | 114 | // Intro text 115 | { 116 | type:"box", 117 | id:"simple_cascade", 118 | text:"simple_cascade", 119 | x:80, y:0, w:800, h:100, 120 | align: "center" 121 | }, 122 | 123 | // Sim 124 | { 125 | type:"sim", 126 | id:"contagion", 127 | x:0, y:-60, 128 | fullscreen: true, 129 | network: { 130 | "contagion":0, 131 | "peeps":CASCADE_PUZZLE.peeps, 132 | "connections":CASCADE_PUZZLE.connections 133 | }, 134 | options:{ 135 | infectedFrame: 1, 136 | scale: 1.25, 137 | startUncuttable: true, 138 | _dunce: true 139 | } 140 | }, 141 | 142 | // UI for the simulation 143 | { 144 | type:"box", 145 | id:"ui", 146 | x:380, y:360, 147 | sim_ui:"red" 148 | }, 149 | 150 | // End text 151 | { 152 | id:"end", 153 | type:"box", 154 | text:"simple_cascade_end", 155 | x:330, y:460, w:300, h:100, 156 | hidden:true 157 | }, 158 | 159 | ], 160 | 161 | onupdate:function(slideshow, state){ 162 | 163 | // Show end if EVERYONE is infected 164 | if(!state.ended){ 165 | var sim = slideshow.simulations.sims[0]; 166 | var peepCount = 0; 167 | sim.peeps.forEach(function(peep){ 168 | if(peep.infected) peepCount++; 169 | }); 170 | if(peepCount==sim.peeps.length){ 171 | var boxes = slideshow.boxes; 172 | boxes.showChildByID("end", true); 173 | state.ended = true; 174 | sim.win({ 175 | small:true, 176 | x:280, y:200, width:400, height:200 177 | }); 178 | } 179 | } 180 | 181 | } 182 | 183 | }, 184 | { 185 | remove:[ 186 | {type:"box", id:"simple_cascade"}, 187 | {type:"box", id:"end"} 188 | ], 189 | move:[ 190 | {type:"box", id:"ui", y:360-80-200}, 191 | {type:"sim", id:"contagion", y:-140-200} 192 | ], 193 | add:[ 194 | { 195 | type:"box", 196 | text:"simple_post_cascade", 197 | x:80, y:210, w:800, h:150, 198 | align: "center" 199 | }/*, 200 | { 201 | type:"box", 202 | text:"simple_post_cascade_end", 203 | x:660, y:450, w:300, h:90 204 | }*/ 205 | ] 206 | }, 207 | ); -------------------------------------------------------------------------------- /js/lib/helpers.js: -------------------------------------------------------------------------------- 1 | ////////////////// 2 | // HELPERS /////// 3 | ////////////////// 4 | 5 | Math.TAU = 6.2831853072; // for true believers 6 | 7 | // The poor man's jQuery 8 | function $(query){ 9 | return document.querySelector(query); 10 | } 11 | function $all(query){ 12 | return [].slice.call(document.querySelectorAll(query)); 13 | } 14 | 15 | // Wide Sigmoid 16 | function sigmoid(x){ 17 | return x / (1 + Math.abs(x)); 18 | } 19 | 20 | // Create retina canvas 21 | function createCanvas(canvas, width, height){ 22 | 23 | // The "canvas" arg not provided? make a new one! 24 | if(arguments.length==2){ 25 | height = arguments[1]; 26 | width = arguments[0]; 27 | canvas = document.createElement("canvas"); 28 | } 29 | 30 | // Set difference in width & height 31 | canvas.width = width*2; 32 | canvas.height = height*2; 33 | canvas.style.width = (width) + "px"; 34 | canvas.style.height = (height) + "px"; 35 | 36 | return canvas; 37 | 38 | } 39 | 40 | // Copy an object 41 | function cloneObject(obj){ 42 | return JSON.parse(JSON.stringify(obj)); 43 | } 44 | 45 | // Get words 46 | function getWords(wordsID){ 47 | return $("words#"+wordsID).innerHTML.trim(); 48 | } 49 | 50 | // Remove from array 51 | function removeFromArray(array, item){ 52 | var index = array.indexOf(item); 53 | if(index>=0) array.splice(index,1); 54 | } 55 | 56 | // Fade In 57 | function fadeIn(container, dom){ 58 | dom.style.opacity = 0; 59 | dom.classList.add("transitionable"); 60 | dom.style.display = "block"; 61 | if(!container.contains(dom)) container.appendChild(dom); 62 | setTimeout(function(){ 63 | dom.style.opacity = 1; 64 | },50); 65 | } 66 | function fadeOut(container, dom){ 67 | dom.classList.add("transitionable"); 68 | dom.style.opacity = 0; 69 | setTimeout(function(){ 70 | if(container.contains(dom)) container.removeChild(dom); 71 | },300); 72 | } 73 | 74 | // Tween position 75 | function tweenPosition(from, to, callback, ease, speed){ 76 | var x1 = from.x; 77 | var y1 = from.y; 78 | var x2 = to.x; 79 | var y2 = to.y; 80 | var dx = x2-x1; 81 | var dy = y2-y1; 82 | var t = 0; 83 | ease = ease || easeInOutSine; 84 | speed = speed || 3/60; 85 | var handle = subscribe("update", function(){ 86 | 87 | // Time 88 | t += speed; 89 | if(t>=1){ 90 | from.x = x2; 91 | from.y = y2; 92 | unsubscribe(handle); 93 | return; 94 | } 95 | 96 | // Update 97 | from.x = x1 + dx*easeInOutSine(t); 98 | from.y = y1 + dy*easeInOutSine(t); 99 | 100 | // Callback 101 | if(callback){ 102 | callback(from); 103 | } 104 | 105 | }); 106 | } 107 | /*function tweenBox(box, to){ 108 | var from = { 109 | x: parseInt(box.style.left), 110 | y: parseInt(box.style.top) 111 | }; 112 | to.x = (to.x===undefined) ? from.x : to.x; 113 | to.y = (to.y===undefined) ? from.y : to.y; 114 | tweenPosition(from, to, function(position){ 115 | box.style.left = position.x + "px"; 116 | box.style.top = position.y + "px"; 117 | }); 118 | }*/ 119 | // From Robert Penner: http://robertpenner.com/scripts/easing_equations.txt 120 | function easeInOutSine(t) { 121 | return -1/2 * (Math.cos((Math.TAU/2)*t) - 1); 122 | }; 123 | function easeLinear(t){ 124 | return t; 125 | } 126 | 127 | // Get Bounding Box of points 128 | function getBoundsOfPoints(points){ 129 | var minX=Infinity, minY=Infinity, 130 | maxX=-Infinity, maxY=-Infinity; 131 | points.forEach(function(p){ 132 | if(p.x0){ 53 | self.clear(); 54 | self.scratch.scratchIn(); // Scratch in 55 | } 56 | 57 | // Remove stuff 58 | slide.remove = slide.remove || []; 59 | slide.remove.forEach(function(childConfig){ 60 | var withFade = true; 61 | switch(childConfig.type){ 62 | case "box": 63 | if(self.boxes.getChildByID(childConfig.id)){ 64 | self.boxes.removeChildByID(childConfig.id, withFade); 65 | } 66 | break; 67 | case "sim": 68 | //self.simulations.removeChildByID(childConfig); 69 | break; 70 | } 71 | }); 72 | 73 | // Move stuff 74 | slide.move = slide.move || []; 75 | slide.move.forEach(function(childConfig){ 76 | switch(childConfig.type){ 77 | case "box": 78 | var box = self.boxes.getChildByID(childConfig.id); 79 | box.classList.add("transitionable"); 80 | var from = { 81 | x: parseInt(box.style.left), 82 | y: parseInt(box.style.top) 83 | }; 84 | var to = { 85 | x: (childConfig.x===undefined) ? from.x : childConfig.x, 86 | y: (childConfig.y===undefined) ? from.y : childConfig.y 87 | }; 88 | box.style.left = to.x+"px"; 89 | box.style.top = to.y+"px"; 90 | break; 91 | case "sim": 92 | var sim = self.simulations.getChildByID(childConfig.id); 93 | var newPosition = { 94 | x: (childConfig.x===undefined) ? sim.config.x : childConfig.x, 95 | y: (childConfig.y===undefined) ? sim.config.y : childConfig.y 96 | }; 97 | tweenPosition(sim.config, newPosition); 98 | break; 99 | } 100 | }); 101 | 102 | // Add stuff 103 | slide.add = slide.add || []; 104 | var _delayAdd = ((slide.remove.length + slide.move.length)>0) ? _delay : 0; 105 | _setTimeout(function(){ 106 | var withFade = ((slide.remove.length + slide.move.length)>0); 107 | 108 | slide.add.forEach(function(childConfig){ 109 | switch(childConfig.type){ 110 | case "box": 111 | self.boxes.add(childConfig, withFade); 112 | break; 113 | case "sim": 114 | if(childConfig.ONLY_IF_IT_DOESNT_ALREADY_EXIST 115 | && self.simulations.sims.length>0){ 116 | // then nothing 117 | }else{ 118 | self.simulations.add(childConfig, withFade); 119 | } 120 | break; 121 | } 122 | }) 123 | 124 | }, _delayAdd); 125 | 126 | // I'm the new slide now 127 | self.currentSlide = slide; 128 | 129 | // On start (if any) 130 | self.currentState = {}; 131 | if(slide.onstart) slide.onstart(self, self.currentState); 132 | 133 | // Transition done... sorta! 134 | _setTimeout(function(){ 135 | self.IS_TRANSITIONING = false; 136 | },800); 137 | 138 | }, _delayNewSlide); 139 | 140 | // Tell everyone it's a new chapter 141 | if(slide.chapter && slide.chapter.indexOf("-")<0){ // is chapter and not sub-chapter 142 | publish("slideshow/goto/",[slide.chapter]); 143 | } 144 | 145 | }; 146 | var _setTimeout = function(callback, delay){ 147 | if(delay==0) return callback(); 148 | else setTimeout(callback, delay); 149 | }; 150 | self.gotoChapter = function(chapterID){ 151 | var index = SLIDES.findIndex(function(slide){ 152 | return slide.chapter == chapterID; 153 | }); 154 | self.goto(index, true); 155 | }; 156 | self.next = function(){ 157 | if(self.slideIndex >= SLIDES.length-1) return; // there's no next 158 | self.goto(self.slideIndex+1); 159 | }; 160 | 161 | // Clear out the DOM 162 | self.clear = function(){ 163 | self.boxes.clear(); 164 | self.simulations.clear(); 165 | self.dom.innerHTML = ""; 166 | pencil.gotoFrame(0); 167 | }; 168 | 169 | // Update 170 | self.update = function(){ 171 | var slide = self.currentSlide; 172 | if(slide){ 173 | self.simulations.update(); 174 | if(slide.onupdate) slide.onupdate(self, self.currentState); 175 | } 176 | }; 177 | 178 | // Draw 179 | self.draw = function(){ 180 | self.simulations.draw(); 181 | } 182 | 183 | } 184 | 185 | //////////////////////////////// 186 | // BUTTON SOUNDS COZ WHATEVER // 187 | //////////////////////////////// 188 | 189 | var _BUTTON_SOUND = 0; 190 | subscribe("sound/button",function(){ 191 | _BUTTON_SOUND = (_BUTTON_SOUND+1)%3; 192 | SOUNDS["button"+_BUTTON_SOUND].play(); 193 | }); -------------------------------------------------------------------------------- /js/slideshow/SandboxUI.js: -------------------------------------------------------------------------------- 1 | function SandboxUI(container){ 2 | 3 | var self = this; 4 | self.container = container; 5 | self.container.classList.add("sandbox_ui"); 6 | 7 | ////////////////////// 8 | // Contagion Slider // 9 | ////////////////////// 10 | 11 | var contagionLabel = document.createElement("div"); 12 | var contagionInput = document.createElement("input"); 13 | contagionInput.type = "range"; 14 | contagionInput.min = 0; 15 | contagionInput.max = 1; 16 | contagionInput.step = 0.05; 17 | contagionInput.value = 0.25; 18 | contagionInput.oninput = function(){ 19 | _updateContagion(); 20 | }; 21 | contagionInput.ontouchstart = function(event){ 22 | event.stopPropagation(); // AHHHH MOBILE 23 | }; 24 | contagionInput.ontouchmove = function(event){ 25 | event.stopPropagation(); // AHHHH MOBILE 26 | }; 27 | var _labelContagion0 = getWords("sandbox_contagion"); 28 | var _labelContagion1 = getWords("sandbox_contagion_simple"); 29 | var _labelContagion2 = getWords("sandbox_contagion_complex"); 30 | var _updateContagion = function(){ 31 | 32 | // update sim 33 | var contagion = contagionInput.value; 34 | slideshow.simulations.sims[0].contagion = contagion; 35 | 36 | // update label 37 | var label = _labelContagion0+" "; 38 | label += Math.round(contagion*100)+"% "; 39 | label += "("+((contagion==0) ? _labelContagion1 : _labelContagion2)+")"; 40 | contagionLabel.innerHTML = label; 41 | 42 | }; 43 | container.appendChild(contagionLabel); 44 | container.appendChild(contagionInput); 45 | setTimeout(function(){ 46 | _updateContagion(); 47 | },1); 48 | 49 | /////////////////////////// 50 | // Choose Color of Peeps // 51 | /////////////////////////// 52 | 53 | var colorChooserLabel = document.createElement("div"); 54 | colorChooserLabel.innerHTML = getWords("sandbox_color_chooser"); 55 | colorChooserLabel.style.marginTop = "0.5em"; 56 | var colorChooser = new ChooseOne({ 57 | options:[ 58 | 1, // red 59 | 2, // yellow 60 | 3, // blue 61 | 4, // green 62 | 5, // pink 63 | ], 64 | makeButton:function(value){ 65 | var button = document.createElement("div"); 66 | button.className = "choose_color"; 67 | button.style.backgroundPosition = (-40*value)+"px 0px"; 68 | return button; 69 | }, 70 | oninput:function(value){ 71 | // update sim 72 | slideshow.simulations.sims[0].options.infectedFrame = value; 73 | } 74 | }); 75 | container.appendChild(colorChooserLabel); 76 | container.appendChild(colorChooser.dom); 77 | 78 | //////////////////////////// 79 | // Choose Tool for Pencil // 80 | //////////////////////////// 81 | 82 | var toolChooserLabel = document.createElement("div"); 83 | toolChooserLabel.innerHTML = getWords("sandbox_tool_chooser"); 84 | toolChooserLabel.style.marginTop = "0.25em"; 85 | var tools = [ 86 | "pencil", 87 | "add", 88 | "add_infected", 89 | "move", 90 | "delete", 91 | "clear" 92 | ]; 93 | var toolChooser = new ChooseOne({ 94 | options:tools, 95 | makeButton: function(value){ 96 | 97 | var button = document.createElement("div"); 98 | button.className = "choose_tool"; 99 | 100 | // Icon 101 | var buttonImage = document.createElement("div"); 102 | button.appendChild(buttonImage); 103 | buttonImage.id = "icon"; 104 | var frame = tools.indexOf(value); 105 | buttonImage.style.backgroundPosition = (-16*frame)+"px 0px"; 106 | 107 | // Label 108 | var buttonLabel = document.createElement("span"); 109 | button.appendChild(buttonLabel); 110 | buttonLabel.innerHTML = getWords("sandbox_tool_"+value); 111 | 112 | return button; 113 | 114 | }, 115 | oninput:function(value){ 116 | // update sim 117 | var sandbox_state = tools.indexOf(value); 118 | slideshow.simulations.sims[0].connectorCutter.sandbox_state = sandbox_state; 119 | } 120 | }); 121 | container.appendChild(toolChooserLabel); 122 | container.appendChild(toolChooser.dom); 123 | 124 | //////////////////////// 125 | // Keyboard Shortcuts // 126 | //////////////////////// 127 | 128 | var shortcutsLabel = document.createElement("div"); 129 | shortcutsLabel.innerHTML = getWords("sandbox_shortcuts_label"); 130 | shortcutsLabel.id = "sandbox_shortcuts_label"; 131 | shortcutsLabel.style.marginTop = "0.5em"; 132 | shortcutsLabel.style.lineHeight = "1.2em"; 133 | var shortcuts = document.createElement("div"); 134 | shortcuts.innerHTML = getWords("sandbox_shortcuts"); 135 | shortcuts.id = "sandbox_shortcuts"; 136 | container.appendChild(shortcutsLabel); 137 | container.appendChild(shortcuts); 138 | 139 | // HEY IT'S SANDBOX MODE // 140 | slideshow.simulations.sims[0].SANDBOX_MODE = true; 141 | 142 | 143 | } 144 | 145 | function ChooseOne(config){ 146 | 147 | var self = this; 148 | 149 | // Container 150 | self.dom = document.createElement("div"); 151 | self.dom.className = "choose_one"; 152 | 153 | // Make Buttons 154 | var buttons = []; 155 | config.options.forEach(function(option){ 156 | 157 | var buttonConfig = option;//.button; 158 | var value = option;//.value; 159 | 160 | // New Button 161 | var buttonDOM = config.makeButton(buttonConfig); 162 | self.dom.appendChild(buttonDOM); 163 | buttons.push(buttonDOM); 164 | 165 | // On Input 166 | buttonDOM.onclick = function(){ 167 | publish("sound/button"); 168 | self.highlight(buttonDOM); // highlight 169 | config.oninput(value); // input 170 | }; 171 | _stopPropButton(buttonDOM); 172 | 173 | }); 174 | 175 | // Highlight 176 | self.highlight = function(toHighlight){ 177 | buttons.forEach(function(button){ 178 | button.removeAttribute("selected"); 179 | }); 180 | toHighlight.setAttribute("selected",true); 181 | }; 182 | self.highlight(buttons[0]); // highlight 1st one always, whatever 183 | 184 | } 185 | 186 | -------------------------------------------------------------------------------- /js/sim/ConnectorCutter.js: -------------------------------------------------------------------------------- 1 | function ConnectorCutter(config){ 2 | 3 | var self = this; 4 | self.config = config; 5 | self.sim = config.sim; 6 | 7 | // Connecting/Cutting 8 | self.connectFrom = null; 9 | self.connectTo = null; 10 | self.isCutting = false; 11 | self.cutTrail = []; 12 | 13 | // SNIP & PLUCK SOUND 14 | var _SNIP_SOUND = 0; 15 | var _SNIP = function(){ 16 | _SNIP_SOUND = (_SNIP_SOUND+1)%3; 17 | SOUNDS["snip"+_SNIP_SOUND].play(); 18 | }; 19 | var _PLUCK_SOUND_INDEX = 0; 20 | var _PLUCK_SOUND = [0,1,2,3,2,1]; 21 | var _PLUCK = function(){ 22 | var soundName = "pluck"+_PLUCK_SOUND[_PLUCK_SOUND_INDEX]; 23 | SOUNDS[soundName].play(); 24 | _PLUCK_SOUND_INDEX++; 25 | if(_PLUCK_SOUND_INDEX >= _PLUCK_SOUND.length) _PLUCK_SOUND_INDEX=0; 26 | }; 27 | 28 | // Update! 29 | self.state = 0; // 0-nothing | 1-connecting | 2-cutting 30 | self.sandbox_state = 0; // 0-pencil | 1-add_peep | 2-add_infected | 3-move | 4-delete | 5-bomb 31 | self.update = function(){ 32 | 33 | var mouse = self.sim.mouse; 34 | 35 | // TOTAL HACK: if you're clicking within the sandbox UI, FORGET IT 36 | if(self.sim.SANDBOX_MODE){ 37 | if(mouse.x>0 && mouse.x<280){ 38 | if(mouse.justPressed){ 39 | return; // FORGET ITTTTTT 40 | } 41 | } 42 | } 43 | 44 | // IF SANDBOX STATE = PENCIL, complex mouse shtuff 45 | if(self.sandbox_state==0){ 46 | 47 | // JUST CLICKED & SIM'S RUNNING? STOP 48 | if(Simulations.IS_RUNNING && mouse.justPressed){ 49 | Simulations.IS_RUNNING = false; 50 | publish("sim/stop"); 51 | } 52 | 53 | // only if sim is NOT RUNNING 54 | if(!Simulations.IS_RUNNING){ 55 | 56 | // JUST CLICKED, and state=0... can either start connecting or cutting! 57 | if(mouse.justPressed && self.state===0){ 58 | 59 | // Clicked on a peep? 60 | var peepClicked = self.sim.getHoveredPeep(20); 61 | if(peepClicked){ 62 | 63 | self.state = 1; // START CONNECTING 64 | self.connectFrom = peepClicked; 65 | 66 | // SOUND! 67 | SOUNDS.pencil_short.volume(0.37); 68 | SOUNDS.pencil_short.play(); 69 | 70 | }else{ 71 | self.state = 2; // START ERASING 72 | } 73 | 74 | } 75 | 76 | // JUST RELEASED, and state!=0... can either stop connecting or cutting! 77 | if(mouse.justReleased && self.state!==0){ 78 | 79 | // End connect? 80 | if(self.state==1){ 81 | var peepReleased = self.sim.getHoveredPeep(20); 82 | if(peepReleased){ 83 | var successfulConnection = self.sim.addConnection(self.connectFrom, peepReleased); 84 | 85 | // SOUND! 86 | if(successfulConnection){ 87 | SOUNDS.pencil.volume(0.37); 88 | SOUNDS.pencil.play(); 89 | } 90 | 91 | } 92 | } 93 | 94 | // back to normal 95 | self.state = 0; 96 | 97 | } 98 | 99 | }else{ 100 | self.state = 0; 101 | } 102 | 103 | // In "NORMAL" state... tell Pencil what frame to go to 104 | if(self.state==0){ 105 | if(!Simulations.IS_RUNNING){ 106 | var peepHovered = self.sim.getHoveredPeep(20); 107 | pencil.gotoFrame( peepHovered ? 1 : 0 ); 108 | }else{ 109 | pencil.gotoFrame(0); 110 | } 111 | } 112 | 113 | // In "CONNECTING" state... show where to connect to 114 | if(self.state==1){ 115 | 116 | // Connect to a nearby hovered peep? 117 | var peepHovered = self.sim.getHoveredPeep(20); 118 | if(peepHovered==self.connectFrom) peepHovered=null; // if same, nah 119 | self.connectTo = peepHovered ? peepHovered : mouse; 120 | 121 | // Pencil's always DARK 122 | pencil.gotoFrame(1); 123 | 124 | } 125 | 126 | // In "CUTTING" state... cut intersected lines! & add to trail 127 | if(self.state==2){ 128 | 129 | // Try cutting 130 | var line = [mouse.lastX, mouse.lastY, mouse.x, mouse.y]; 131 | var wasLineCut = self.sim.tryCuttingConnections(line); 132 | if(wasLineCut==1){ // snip! 133 | _SNIP(); 134 | } 135 | if(wasLineCut==-1){ // uncuttable 136 | _PLUCK(); 137 | } 138 | 139 | // Add to trail 140 | self.cutTrail.unshift([mouse.x,mouse.y]); // add to start 141 | 142 | // Pencil's always RED 143 | pencil.gotoFrame(2); 144 | 145 | } 146 | 147 | }else{ 148 | self.state=0; 149 | } 150 | 151 | // IF SANDBOX STATE = ADD/DELETE PEEP or BOMB, just click to activate! 152 | if(self.sandbox_state!=0){ 153 | if(mouse.justPressed){ 154 | 155 | // Add Peep 156 | if(self.sandbox_state==1){ 157 | self.sim._addPeepAtMouse(false); // not infected 158 | } 159 | 160 | // Add Infected Peep 161 | if(self.sandbox_state==2){ 162 | self.sim._addPeepAtMouse(true); // IS infected 163 | } 164 | 165 | // Delete Peep 166 | if(self.sandbox_state==4){ 167 | self.sim._deletePeep(); 168 | } 169 | 170 | // BOMB 171 | if(self.sandbox_state==5){ 172 | var contagionLevel = self.sim.contagion; // hack for sandbox: keep contagion the same 173 | self.sim.clear(); 174 | self.sim.contagion = contagionLevel; 175 | 176 | // Sound! 177 | SOUNDS.boom.play(); 178 | 179 | } 180 | 181 | } 182 | } 183 | 184 | // IF SANDBOX STATE = MOVE... 185 | if(self.sandbox_state==3){ 186 | if(mouse.justPressed) self.sim._startMove(); 187 | if(mouse.justReleased) self.sim._stopMove(); 188 | } 189 | 190 | // If trail too long, or NOT cutting, pop trail from end 191 | if(self.cutTrail.length>10 || self.state!=2 || self.sandbox_state!=0){ 192 | self.cutTrail.pop(); 193 | } 194 | 195 | }; 196 | 197 | // Draw 198 | self.draw = function(ctx){ 199 | 200 | ctx.lineJoin = "round"; 201 | ctx.lineCap = "round"; 202 | 203 | // Connecting! 204 | if(self.state==1){ 205 | var tempConnection = new Connection({ 206 | from:self.connectFrom, to:self.connectTo, 207 | sim:self.sim 208 | }); 209 | ctx.save(); 210 | ctx.globalAlpha = 0.5; 211 | tempConnection.draw(ctx); 212 | ctx.restore(); 213 | } 214 | 215 | // Cutting! 216 | if(self.cutTrail.length>0){ 217 | ctx.strokeStyle = "#dd4040"; 218 | ctx.lineWidth = 2; 219 | ctx.beginPath(); 220 | ctx.moveTo(self.cutTrail[0][0], self.cutTrail[0][1]); 221 | for(var i=1; i -------------------------------------------------------------------------------- /js/chapters/E_Complex_Contagion.js: -------------------------------------------------------------------------------- 1 | // 3 - Complex Contagion 2 | 3 | SLIDES.push( 4 | 5 | { 6 | chapter: "Complex", 7 | clear:true, 8 | 9 | add:[ 10 | 11 | // Intro text 12 | { 13 | type:"box", 14 | id:"complex_complex", 15 | text:"complex_complex", 16 | x:0, y:0, w:480, h:540 17 | }, 18 | 19 | // Sim 20 | { 21 | type:"sim", 22 | x:0, y:0, 23 | fullscreen: true, 24 | network: { 25 | "contagion":0.5, 26 | "peeps":[[849,356,0],[808,199,0],[543,97,1],[679,114,0],[781,480,0],[906,480,0]], 27 | "connections":[[0,1,1],[2,3,1],[3,1,1],[4,0,1],[0,5,1]] 28 | }, 29 | options:{ 30 | infectedFrame: 2, 31 | scale: 1.75, 32 | startUncuttable: true, 33 | _bottle: true 34 | } 35 | }, 36 | 37 | // UI for the simulation 38 | { 39 | type:"box", 40 | x:520, y:230, 41 | sim_ui:"red" 42 | } 43 | 44 | ], 45 | 46 | onupdate:function(slideshow, state){ 47 | 48 | // Show next if SIM STEP >= 3 49 | if(!state.ended){ 50 | var sim = slideshow.simulations.sims[0]; 51 | if(sim.STEP>=3){ 52 | state.ended = true; 53 | slideshow.next(); 54 | } 55 | } 56 | 57 | } 58 | 59 | }, 60 | 61 | { 62 | remove:[ 63 | {type:"box", id:"complex_complex"} 64 | ], 65 | add:[ 66 | { 67 | type:"box", 68 | text:"complex_complex_2", 69 | x:0, y:0, w:480, h:540 70 | } 71 | ] 72 | }, 73 | 74 | { 75 | chapter: "Complex-Wisdom", 76 | clear:true, 77 | 78 | add:[ 79 | 80 | // Intro text 81 | { 82 | id:"complex_complex_3", 83 | type:"box", 84 | text:"complex_complex_3", 85 | x:480, y:0, w:480, h:540 86 | }, 87 | 88 | // Sim 89 | { 90 | type:"sim", 91 | x:0, y:0, 92 | fullscreen: true, 93 | network: { 94 | "contagion":0.25, 95 | "peeps":[[54,240,1],[227,237,0],[298,98,0],[405,157,0],[408,296,0],[311,380,0]], 96 | "connections":[[1,2,0],[1,3,0],[4,1,0],[1,5,0],[0,1,0]] 97 | }, 98 | options:{ 99 | infectedFrame: 3, 100 | scale: 1.75, 101 | _wisdom: true 102 | } 103 | }, 104 | 105 | // UI for the simulation 106 | { 107 | type:"box", 108 | x:30, y:320, 109 | sim_ui:"red" 110 | } 111 | 112 | ], 113 | 114 | onupdate:function(slideshow, state){ 115 | 116 | // Show end if EVERYONE is infected 117 | if(!state.ended){ 118 | var sim = slideshow.simulations.sims[0]; 119 | var peepCount = 0; 120 | sim.peeps.forEach(function(peep){ 121 | if(peep.infected) peepCount++; 122 | }); 123 | if(peepCount==sim.peeps.length){ 124 | var boxes = slideshow.boxes; 125 | state.ended = true; 126 | sim.win({ 127 | small:true 128 | }); 129 | slideshow.next(); 130 | } 131 | } 132 | 133 | } 134 | 135 | }, 136 | 137 | { 138 | remove:[ 139 | {type:"box", id:"complex_complex_3"} 140 | ], 141 | add:[ 142 | { 143 | id:"end", 144 | type:"box", 145 | text:"complex_complex_3_end", 146 | x:480, y:0, w:480, h:540 147 | } 148 | ] 149 | }, 150 | 151 | { 152 | chapter: "Complex-Cascade", 153 | clear:true, 154 | 155 | add:[ 156 | 157 | // Intro text 158 | { 159 | type:"box", 160 | id:"complex_cascade", 161 | text:"complex_cascade", 162 | x:60, y:0, w:840, h:100, 163 | align: "center" 164 | }, 165 | 166 | // Sim 167 | { 168 | type:"sim", 169 | id:"contagion", 170 | x:0, y:-40, 171 | fullscreen: true, 172 | network: { 173 | "contagion":0.25, 174 | "peeps":CASCADE_PUZZLE.peeps, 175 | "connections":CASCADE_PUZZLE.connections 176 | }, 177 | options:{ 178 | infectedFrame: 3, 179 | scale: 1.25, 180 | startUncuttable: true, 181 | _wisdom: true 182 | } 183 | }, 184 | 185 | // UI for the simulation 186 | { 187 | type:"box", 188 | id:"ui", 189 | x:380, y:370, 190 | sim_ui:"red" 191 | }, 192 | { 193 | type:"box", 194 | id:"complex_cascade_feel_free", 195 | text:"complex_cascade_feel_free", 196 | x:330, y:440, w:300, h:100, 197 | align: "center" 198 | }, 199 | 200 | // End text 201 | { 202 | id:"end", 203 | type:"box", 204 | text:"complex_cascade_end", 205 | x:330, y:450, w:300, h:100, 206 | hidden:true 207 | }, 208 | 209 | ], 210 | 211 | onupdate:function(slideshow, state){ 212 | 213 | // Show end if EVERYONE is infected 214 | if(!state.ended){ 215 | var sim = slideshow.simulations.sims[0]; 216 | var peepCount = 0; 217 | sim.peeps.forEach(function(peep){ 218 | if(peep.infected) peepCount++; 219 | }); 220 | if(peepCount==sim.peeps.length){ 221 | var boxes = slideshow.boxes; 222 | boxes.removeChildByID("complex_cascade_feel_free", true); 223 | boxes.showChildByID("end", true); 224 | state.ended = true; 225 | sim.win(); 226 | } 227 | } 228 | 229 | } 230 | 231 | }, 232 | 233 | { 234 | remove:[ 235 | {type:"box", id:"complex_cascade"}, 236 | {type:"box", id:"end"} 237 | ], 238 | move:[ 239 | {type:"box", id:"ui", y:360-80}, 240 | {type:"sim", id:"contagion", y:-140} 241 | ], 242 | add:[ 243 | { 244 | type:"box", 245 | text:"complex_post_cascade", 246 | x:50, y:390, w:600, h:150, 247 | align: "right" 248 | }, 249 | { 250 | type:"box", 251 | text:"complex_post_cascade_end", 252 | x:660, y:450, w:300, h:90 253 | } 254 | ] 255 | }, 256 | 257 | { 258 | chapter: "Complex-Prevent", 259 | clear:true, 260 | 261 | add:[ 262 | 263 | // Intro text 264 | { 265 | type:"box", 266 | id:"complex_prevent", 267 | text:"complex_prevent", 268 | x:80, y:0, w:800, h:140, 269 | align: "center" 270 | }, 271 | 272 | // Lil' contagion 273 | { 274 | id: "contagion", 275 | type:"sim", 276 | x:0, y:80, 277 | fullscreen: true, 278 | network: { 279 | "contagion":0.25, 280 | "peeps":CONTAGION_PUZZLE.peeps, 281 | "connections":CONTAGION_PUZZLE.connections 282 | }, 283 | options:{ 284 | infectedFrame: 3, 285 | scale: 1.25, 286 | startUncuttable: true, 287 | _wisdom: true 288 | } 289 | }, 290 | 291 | // UI for the simulation 292 | { 293 | type:"box", 294 | id:"ui", 295 | x:380, y:140, 296 | sim_ui:"red" 297 | }, 298 | 299 | // Outro text 300 | /*{ 301 | id:"end", 302 | type:"box", 303 | text:"complex_prevent_end", 304 | x:660, y:440, w:300, h:100, 305 | hidden:true 306 | }*/ 307 | 308 | ], 309 | 310 | onupdate:function(slideshow, state){ 311 | 312 | // Show end if sim is running AND no one left to infect 313 | // that is, it's stalled... YAY! 314 | var sim = slideshow.simulations.sims[0]; 315 | 316 | if(!state.ended){ 317 | if(Simulations.IS_RUNNING){ 318 | 319 | // if it's a new step... 320 | if(sim.STEP > state.lastStep){ 321 | 322 | // ...but the infected count is the same as last step 323 | var countInfected = 0; 324 | sim.peeps.forEach(function(peep){ if(peep.infected) countInfected++; }); 325 | if(state.lastInfected == countInfected){ 326 | 327 | // oh, and it's NOT coz ALL of 'em are infected 328 | if(countInfected!=sim.peeps.length){ 329 | 330 | // WIN 331 | state.ended = true; 332 | var boxes = slideshow.boxes; 333 | setTimeout(function(){ 334 | //boxes.showChildByID("end", true); 335 | sim.win({ 336 | x:350, y:270-90, 337 | width:260, height:260, 338 | small:true 339 | }); 340 | },350); 341 | setTimeout(function(){ 342 | slideshow.next(); 343 | },1100); 344 | 345 | } 346 | 347 | }else{ 348 | state.lastInfected = countInfected; 349 | } 350 | 351 | } 352 | state.lastStep = sim.STEP; 353 | 354 | }else{ 355 | state.lastStep = 0; 356 | state.lastInfected = 1; 357 | } 358 | 359 | } 360 | 361 | } 362 | 363 | }, 364 | 365 | { 366 | remove:[ 367 | {type:"box", id:"complex_prevent"} 368 | ], 369 | move:[ 370 | {type:"box", id:"ui", y:0}, 371 | {type:"sim", id:"contagion", y:-70} 372 | ], 373 | add:[ 374 | { 375 | type:"box", 376 | text:"complex_prevent_2", 377 | x:0, y:390, w:650, h:100, 378 | align: "right" 379 | }, 380 | { 381 | type:"box", 382 | text:"complex_prevent_end", 383 | x:660, y:450, w:300, h:90 384 | } 385 | ] 386 | }, 387 | 388 | { 389 | chapter: "Complex-Groupthink", 390 | clear: true, 391 | 392 | add:[ 393 | 394 | // NASA Image 395 | { 396 | type:"box", 397 | img:"sprites/nasa.png", x:0, y:0, w:425, h:450 398 | }, 399 | 400 | // Text 401 | { 402 | type:"box", 403 | text:"complex_groupthink", 404 | x:460, y:0, w:500, h:540 405 | }, 406 | 407 | 408 | ] 409 | 410 | } 411 | 412 | ); 413 | 414 | 415 | -------------------------------------------------------------------------------- /js/chapters/C_Networks.js: -------------------------------------------------------------------------------- 1 | // 1 - NETWORKS 2 | SLIDES.push( 3 | 4 | // PLAY AROUND: how to connect & disconnect 5 | { 6 | 7 | chapter: "Networks", 8 | 9 | clear:true, 10 | add:[ 11 | 12 | // The top instructions 13 | { 14 | type:"box", 15 | text:"networks_tutorial_start", x:260, y:0, w:440, h:70, align:"center" 16 | }, 17 | 18 | // The fullscreen simulation 19 | { 20 | type:"sim", 21 | x:0, y:10, 22 | fullscreen: true, 23 | network: { 24 | "contagion":0, 25 | "peeps":[[44,184,0],[155,215,0],[237,105,0],[309,213,0],[646,211,0],[328,305,0],[629,308,0],[417,111,0],[538,362,0],[216,299,0],[94,314,0],[-61,220,0],[68,455,0],[733,147,0],[760,293,0],[776,437,0],[759,48,0],[134,33,0],[929,181,0],[848,111,0],[1013,330,0],[880,269,0],[538,128,0],[189,388,0],[853,356,0]], 26 | //"connections":[[5,6,0]], 27 | "connections":[[1,0,0],[0,11,0],[2,17,0],[9,23,0],[9,10,0],[9,1,0],[9,5,0],[23,12,0],[3,2,0],[4,13,0],[13,16,0],[13,19,0],[6,14,0],[14,24,0],[14,15,0],[14,21,0],[21,20,0],[21,18,0],[5,6,0]] 28 | } 29 | }, 30 | 31 | // "Connect" instruction (words & picture) 32 | { 33 | type:"box", 34 | id:"connect_words", 35 | text:"networks_tutorial_connect", x:280, y:183-7, w:400, align:"center", color:"#bbb" 36 | }, 37 | { 38 | type:"box", 39 | id:"connect_pic", 40 | img:"sprites/tutorial_connect.png", x:330, y:150-7, w:300, h:100 41 | }, 42 | 43 | // "Disconnect" instruction (words & picture) 44 | { 45 | type:"box", 46 | id:"disconnect_words", 47 | text:"networks_tutorial_disconnect", x:280, y:280, w:400, align:"center", color:"#bbb" 48 | }, 49 | { 50 | type:"box", 51 | id:"disconnect_pic", 52 | img:"sprites/tutorial_disconnect.png", x:327, y:245, w:300, h:100 53 | }, 54 | 55 | // The bottom instructions & button (hidden at first) 56 | { 57 | type:"box", 58 | id:"end_words", 59 | text:"networks_tutorial_end", x:230, y:400, w:500, h:70, align:"center", 60 | hidden:true 61 | } 62 | 63 | ], 64 | 65 | // Logic to fade in/out words & stuff 66 | onupdate:function(slideshow, state){ 67 | 68 | // Count number of connections this & last time 69 | var sim = slideshow.simulations.sims[0]; 70 | var numConnections = sim.connections.length; 71 | if(state.lastConnections===undefined) state.lastConnections=numConnections; 72 | state.currConnections = numConnections; 73 | 74 | // SHOW/HIDE INSTRUCTIONS 75 | var boxes = slideshow.boxes; 76 | // If connections went UP, hide "connect" instructions 77 | if(state.currConnections > state.lastConnections && !state.canConnect){ 78 | state.canConnect = true; 79 | boxes.removeChildByID("connect_words", true); 80 | boxes.removeChildByID("connect_pic", true); 81 | } 82 | // If connections went DOWN, hide "disconnect" instructions 83 | if(state.currConnections < state.lastConnections && !state.canDisconnect){ 84 | state.canDisconnect = true; 85 | boxes.removeChildByID("disconnect_words", true); 86 | boxes.removeChildByID("disconnect_pic", true); 87 | } 88 | // If did both, show end 89 | if(state.canConnect && state.canDisconnect && !state.BUTTON_SHOWED){ 90 | state.BUTTON_SHOWED = true; 91 | boxes.showChildByID("end_words", true); 92 | //boxes.showChildByID("end_button"); 93 | } 94 | 95 | // update # of connections in state 96 | state.lastConnections = state.currConnections; 97 | 98 | } 99 | 100 | }, 101 | 102 | // PLAY AROUND: how the "threshold" model workds 103 | // diagonal 104 | { 105 | 106 | chapter: "Networks-Threshold", 107 | 108 | clear:true, 109 | add:[ 110 | 111 | // TEXT 112 | { 113 | type:"box", 114 | id:"networks_threshold", 115 | text:"networks_threshold", x:60, y:25, w:400 116 | }, 117 | { 118 | type:"box", 119 | id:"networks_threshold_instruction", 120 | text:"networks_threshold_instruction", x:110, y:260, w:300, 121 | align:"center" 122 | }, 123 | /*{ 124 | type:"box", 125 | id:"networks_threshold_explanation", 126 | text:"networks_threshold_explanation", x:205, y:345, w:300, 127 | align:"right", 128 | color:"#bbb", 129 | fontSize:"0.75em", 130 | lineHeight:"1.2em" 131 | },*/ 132 | { 133 | type:"box", 134 | id:"networks_threshold_end", 135 | text:"networks_threshold_end", x:60, y:350, w:400 136 | }, 137 | 138 | // SIMULATION: THRESHOLD 139 | { 140 | type:"sim", 141 | x:420, y:70, 142 | fullscreen: true, 143 | network: { 144 | "contagion":0.5, 145 | "peeps":[[141,99,0],[444,373,1],[442,103,1],[144,371,0]], 146 | "connections":[[2,1,0],[3,2,0]] 147 | }, 148 | options:{ 149 | infectedFrame: 2, 150 | scale: 2, 151 | _bottle: true 152 | } 153 | } 154 | 155 | ] 156 | }, 157 | 158 | // pre-puzzle ramble 159 | { 160 | remove:[ 161 | { type:"box", id:"networks_threshold" }, 162 | { type:"box", id:"networks_threshold_instruction" }, 163 | { type:"box", id:"networks_threshold_explanation" }, 164 | { type:"box", id:"networks_threshold_end" } 165 | ], 166 | add:[ 167 | { 168 | type:"box", 169 | id:"networks_pre_puzzle", 170 | text:"networks_pre_puzzle", x:60, y:0, w:400, 171 | lineHeight:"1.3em" 172 | }, 173 | { 174 | type:"box", 175 | id:"networks_pre_puzzle_2", 176 | text:"networks_pre_puzzle_2", x:60, y:107, w:400, 177 | lineHeight:"1.3em" 178 | }, 179 | { 180 | type:"box", 181 | text:"optional_reading", x:60, y:220, w:400, h:30, 182 | fontSize:"17px", color:"#bbb" 183 | } 184 | ] 185 | }, 186 | 187 | 188 | // PUZZLE: The "Majority Illusion" puzzle 189 | { 190 | 191 | chapter: "Networks-Majority", 192 | 193 | clear:true, 194 | add:[ 195 | 196 | // The puzzle! 197 | { 198 | id:"puzzle", 199 | type:"sim", 200 | x:410, y:25, 201 | fullscreen: true, 202 | network: { 203 | "contagion":0.5, 204 | "peeps":[[106,106,1],[239,52,1],[376,110,1],[27,221,0],[54,365,0],[162,458,0],[308,467,0],[407,371,0],[453,241,0]], 205 | "connections":[], 206 | }, 207 | options:{ 208 | infectedFrame: 2, 209 | scale: 1.5, 210 | _bottle: true 211 | } 212 | }, 213 | 214 | // Done? Let's go... (hidden at first...) 215 | { 216 | type:"box", 217 | id:"networks_puzzle", 218 | text:"networks_puzzle", x:60, y:10, w:300 219 | }, 220 | { 221 | type:"box", 222 | id:"networks_puzzle_metric", 223 | text:"networks_puzzle_metric", x:60, y:220+30, w:300 224 | }, 225 | { 226 | type:"box", 227 | id:"networks_puzzle_end", 228 | text:"networks_puzzle_end", x:60, y:300, w:300, 229 | hidden:true 230 | } 231 | 232 | ], 233 | 234 | onstart:function(slideshow, state){ 235 | 236 | // Modify puzzle metric box 237 | var metric = slideshow.boxes.getChildByID("networks_puzzle_metric"); 238 | metric.innerHTML = ""; 239 | 240 | var COLOR = "hsl(50, 100%, 50%)"; 241 | 242 | // label 243 | var label = document.createElement("div"); 244 | metric.appendChild(label); 245 | label.style.color = COLOR; 246 | 247 | // bar 248 | var bar_container = document.createElement("div"); 249 | metric.appendChild(bar_container); 250 | bar_container.style.border = "2px solid "+COLOR; 251 | bar_container.style.width = "100%"; 252 | bar_container.style.height = "1em"; 253 | bar_container.style.position = "relative"; 254 | var bar = document.createElement("div"); 255 | bar_container.appendChild(bar); 256 | bar.style.background = COLOR; 257 | bar.style.height = "100%"; 258 | bar.style.position = "absolute"; 259 | 260 | // Save this cool DOM into state 261 | state.metric_label = label; 262 | state.metric_bar = bar; 263 | 264 | }, 265 | 266 | onupdate:function(slideshow, state){ 267 | 268 | // How many peeps? 269 | var sim = slideshow.simulations.sims[0]; 270 | var peepCount = 0; 271 | sim.peeps.forEach(function(peep){ 272 | if(peep.isPastThreshold) peepCount++; 273 | }); 274 | 275 | // Modify metric box! 276 | var label = getWords("networks_puzzle_metric") + " " + peepCount + " " + getWords("networks_puzzle_metric_2"); 277 | state.metric_label.innerHTML = label; 278 | state.metric_bar.style.width = Math.round((peepCount/9)*100)+"%"; 279 | 280 | // Win only if EVERYONE hits threshold 281 | if(!state.won){ 282 | if(peepCount==9){ 283 | var boxes = slideshow.boxes; 284 | state.won = true; 285 | boxes.removeChildByID("networks_puzzle_metric", true); 286 | boxes.showChildByID("networks_puzzle_end", true); 287 | sim.win(); 288 | } 289 | } 290 | 291 | } 292 | 293 | }, 294 | 295 | // post-puzzle ramble, introduce simple contagion 296 | { 297 | remove:[ 298 | { type:"box", id:"networks_puzzle" }, 299 | { type:"box", id:"networks_puzzle_metric" }, 300 | { type:"box", id:"networks_puzzle_end" } 301 | ], 302 | move:[ 303 | // shift sim to side 304 | {type:"sim", id:"puzzle", x:20} 305 | ], 306 | add:[ 307 | // new text 308 | { 309 | type:"box", 310 | id:"networks_post_puzzle", 311 | text:"networks_post_puzzle", x:560, y:0, w:400 312 | }, 313 | /*{ 314 | type:"box", 315 | id:"networks_post_puzzle_bonus", 316 | text:"networks_post_puzzle_bonus", x:170, y:1000 // offscreen! 317 | },*/ 318 | ], 319 | 320 | /* 321 | onupdate:function(slideshow, state){ 322 | 323 | // How many peeps passed? 324 | var sim = slideshow.simulations.sims[0]; 325 | var peepCount = 0; 326 | sim.peeps.forEach(function(peep){ 327 | if(peep.numFriends>0 && !peep.isPastThreshold) peepCount++; 328 | }); 329 | 330 | // Win Bonus 331 | if(!state.won){ 332 | if(peepCount==9){ 333 | var winbox = slideshow.boxes.getChildByID("networks_post_puzzle_bonus"); 334 | if(winbox){ 335 | winbox.style.top = "270px"; 336 | state.won = true; 337 | } 338 | } 339 | } 340 | 341 | } 342 | */ 343 | 344 | } 345 | 346 | ); -------------------------------------------------------------------------------- /js/sim/Peep.js: -------------------------------------------------------------------------------- 1 | function Peep(config){ 2 | 3 | var self = this; 4 | 5 | // Properties 6 | self.x = config.x; 7 | self.y = config.y; 8 | self.velocity = {x:0, y:0}; 9 | self.infected = !!config.infected; 10 | self.sim = config.sim; 11 | 12 | // Update: 13 | self.numFriends = 0; 14 | self.numInfectedFriends = 0; 15 | self.isPastThreshold = false; 16 | self.faceX = 0; 17 | self.faceY = 0; 18 | self.faceBlink = 0; 19 | self.isMajority = false; 20 | var _faceFollow = 0.75+(Math.random()*0.1); 21 | self.update = function(){ 22 | 23 | // Face position! 24 | var faceVector = { 25 | x: (self.sim.mouse.x-self.x)/5, 26 | y: (self.sim.mouse.y-self.y)/5 27 | }; 28 | faceVector.mag = Math.sqrt(faceVector.x*faceVector.x + faceVector.y*faceVector.y); 29 | var max_distance = 5; 30 | if(faceVector.mag>max_distance){ 31 | faceVector.x = faceVector.x * (max_distance/faceVector.mag); 32 | faceVector.y = faceVector.y * (max_distance/faceVector.mag); 33 | } 34 | self.faceX = self.faceX*_faceFollow + faceVector.x*(1-_faceFollow); 35 | self.faceY = self.faceY*_faceFollow + faceVector.y*(1-_faceFollow); 36 | 37 | // Blink? 38 | if(!self.faceBlink){ 39 | if(Math.random()<0.002) self.faceBlink=true; 40 | }else{ 41 | if(Math.random()<0.07) self.faceBlink=false; 42 | } 43 | 44 | // Friends connected... or infected 45 | var friends = self.sim.getFriendsOf(self); 46 | self.numFriends = friends.length; 47 | self.numInfectedFriends = 0; 48 | friends.forEach(function(friend){ 49 | if(friend.infected) self.numInfectedFriends++; 50 | }); 51 | 52 | // Past threshold? 53 | self.isPastThreshold = false; 54 | if(self.sim.contagion==0){ 55 | // simple 56 | if(self.numInfectedFriends>0) self.isPastThreshold = true; 57 | }else{ 58 | // complex 59 | if(self.numFriends>0){ 60 | var ratio = self.numInfectedFriends/self.numFriends; 61 | if(ratio>=self.sim.contagion-0.0001){ // floating point errors 62 | self.isPastThreshold = true; 63 | } 64 | } 65 | } 66 | 67 | // SPLASH: FORCE-DIRECTED 68 | if(self.sim.options.splash){ 69 | 70 | // Attract towards 0 (gravity increases slightly the further you get out) 71 | var gravity = getUnitVector({ 72 | x: 0 - self.x, 73 | y: 0 - self.y 74 | }); 75 | var gravityScale = getVectorLength(self)*0.00012; 76 | if(self.sim.options.CONCLUSION){ 77 | gravityScale *= 2; 78 | } 79 | gravity = multiplyVector(gravity, gravityScale); 80 | self.velocity = addVectors(self.velocity, gravity); 81 | 82 | // If within the ring, push OUT. 83 | if(!self.sim.options.CONCLUSION){ 84 | var RADIUS = 325; 85 | var distanceFromCenter = getVectorLength(self); 86 | if(distanceFromCenter=0) return; // not a friend 122 | 123 | var fromTo = getVectorFromTo(self, peep); 124 | var d = getVectorLength(fromTo); 125 | var forceMagnitude = c/(d*d); 126 | var force = multiplyVector( getUnitVector(fromTo), forceMagnitude ); 127 | 128 | coulombTotalForce = addVectors(coulombTotalForce, force); 129 | 130 | }); 131 | self.velocity = addVectors(self.velocity, coulombTotalForce); 132 | 133 | // Travel Clockwise 134 | var spin = getUnitVector(self); 135 | spin = rotateVector(spin, Math.TAU/4); 136 | spin = multiplyVector(spin, 0.02*0.25); // even less spin 137 | self.velocity = addVectors(self.velocity, spin); 138 | 139 | // Air Friction 140 | self.velocity = multiplyVector(self.velocity, 0.95); 141 | 142 | // Move 143 | self.x += self.velocity.x; 144 | self.y += self.velocity.y; 145 | 146 | } 147 | 148 | }; 149 | 150 | // Body Sprite 151 | var _initSpriteScale = 0.3; 152 | self.sprite = new Sprite({ 153 | img: "peeps", 154 | frames:6, sw:200, sh:200, 155 | }); 156 | self.sprite.pivotX = 100; 157 | self.sprite.pivotY = 100; 158 | self.sprite.scale = _initSpriteScale; 159 | 160 | // Prop Sprite 161 | self.propSprite = new Sprite({ 162 | img: "peeps", 163 | frames:6, sw:200, sh:200, 164 | }); 165 | self.propSprite.pivotX = 100; 166 | self.propSprite.pivotY = 100; 167 | self.propSprite.scale = _initSpriteScale; 168 | var _bottleAnim = Math.random()*Math.TAU; 169 | var _bottleSpeed = 0.01 + Math.random()*0.01; 170 | 171 | // Draw 172 | var radius = 25; 173 | var barWidth = radius*2; 174 | var barHeight = 10; 175 | var bodyRotation = Math.TAU*Math.random(); 176 | var PEEP_COLORS = [ 177 | "#B4B4B4", // gray 178 | "#F73C50", // red 179 | "#FEE576", // yellow 180 | "#86F5FB", // blue 181 | "#7DE74E", // green 182 | "#FBCBDC" // pink 183 | ]; 184 | var _glowAnim = 0; 185 | self.conclusionFrame = Math.floor(1+Math.random()*5); 186 | self.draw = function(ctx){ 187 | 188 | ctx.save(); 189 | ctx.translate(self.x, self.y); 190 | 191 | var s; 192 | if(s = self.sim.options.scale) ctx.scale(s,s); 193 | 194 | // Circle 195 | var infectedFrame = self.sim.options.infectedFrame || 1; 196 | var infectedColor = PEEP_COLORS[infectedFrame]; 197 | var myFrame = self.infected ? infectedFrame : 0; 198 | var myColor = PEEP_COLORS[myFrame]; 199 | // CONCLUSION SPLASH 200 | if(self.sim.options.CONCLUSION){ 201 | var distance = getVectorLength(self); 202 | if(distance < self.sim.options.CONCLUSION_GLOW_RADIUS){ 203 | //self.isPastThreshold = true; 204 | myFrame = self.conclusionFrame; 205 | infectedFrame = self.conclusionFrame; 206 | } 207 | } 208 | self.sprite.rotation = bodyRotation; 209 | if(self.isPastThreshold){ // highlight! glow! 210 | 211 | _glowAnim += 0.03; 212 | var _glowScale = 1 + Math.sin(_glowAnim)*0.04; 213 | ctx.globalAlpha = 0.35; 214 | self.sprite.scale = _initSpriteScale*1.25*_glowScale; 215 | 216 | self.sprite.gotoFrame(infectedFrame); 217 | self.sprite.draw(ctx); 218 | 219 | // undo 220 | ctx.globalAlpha = 1; 221 | self.sprite.scale = _initSpriteScale; 222 | 223 | } 224 | self.sprite.gotoFrame(myFrame); 225 | self.sprite.draw(ctx); 226 | 227 | // Face 228 | ctx.save(); 229 | ctx.translate(self.faceX, self.faceY); 230 | self.sprite.rotation = 0; 231 | self.sprite.gotoFrame(self.faceBlink ? 7 : 6); 232 | if(self.sim.options._wisdom && self.infected){ 233 | self.sprite.gotoFrame(10); 234 | } 235 | if(self.sim.options._bottle && self.infected){ 236 | self.sprite.rotation = Math.sin(_bottleAnim*1.5)*0.15; 237 | } 238 | self.sprite.draw(ctx); 239 | ctx.restore(); 240 | 241 | // PROPS? 242 | if(self.sim.options._bottle && self.infected){ 243 | self.propSprite.x = 25; 244 | self.propSprite.y = 15; 245 | _bottleAnim += _bottleSpeed; 246 | self.propSprite.scale = 0.25; 247 | self.propSprite.rotation = 0.2 + Math.sin(_bottleAnim)*0.2; 248 | self.propSprite.gotoFrame(9); 249 | self.propSprite.draw(ctx); 250 | } 251 | if(self.sim.options._dunce && self.infected){ 252 | self.propSprite.x = -14; 253 | self.propSprite.y = -22; 254 | self.propSprite.scale = 0.25; 255 | self.propSprite.gotoFrame(8); 256 | self.propSprite.draw(ctx); 257 | } 258 | 259 | ////////////////////////////////////////////////////////// 260 | // LABEL FOR INFECTED/FRIENDS, BAR, AND CONTAGION LEVEL // 261 | ////////////////////////////////////////////////////////// 262 | 263 | // DON'T show bar if simple contagion 264 | if(self.sim.contagion>0){ 265 | 266 | ctx.save(); 267 | 268 | // SHAKE 269 | if(self._shakeAnim>=0){ 270 | var shake = Math.sin(self._shakeAnim*10)*3; 271 | ctx.translate(shake, 0); 272 | self._shakeAnim -= 0.05; 273 | } 274 | 275 | var bgColor = "#ddd"; 276 | var uiColor = "#333"; 277 | 278 | // Say: Infected/Friends (% then n/n) 279 | ctx.translate(0,-46); 280 | ctx.font = '12px PatrickHand'; 281 | ctx.fillStyle = uiColor; 282 | ctx.textBaseline = "middle"; 283 | ctx.fontWeight = "bold"; 284 | if(self.numFriends>0){ 285 | 286 | // %, centered 287 | ctx.textAlign = "center"; 288 | var labelPercent = Math.round(100*(self.numInfectedFriends/self.numFriends)) + "%"; 289 | ctx.fillText(labelPercent, 0, 0); 290 | 291 | /* 292 | // % 293 | ctx.textAlign = "left"; 294 | var labelPercent = Math.round(100*(self.numInfectedFriends/self.numFriends)) + "%"; 295 | ctx.fillText(labelPercent, -barWidth/2, 0); 296 | 297 | // #/# 298 | ctx.textAlign = "right"; 299 | var labelNum = self.numInfectedFriends+"/"+self.numFriends; 300 | ctx.fillText(labelNum, barWidth/2, 0); 301 | */ 302 | 303 | 304 | }else{ 305 | ctx.textAlign = "center"; 306 | ctx.fillText("∅", 0, -1); 307 | } 308 | 309 | // the gray bg 310 | ctx.translate(0,13); 311 | ctx.fillStyle = bgColor; 312 | ctx.beginPath(); 313 | ctx.rect(-barWidth/2, -barHeight/2, barWidth, barHeight); 314 | ctx.fill(); 315 | 316 | // the color fill 317 | if(self.numFriends>0){ 318 | ctx.fillStyle = infectedColor; 319 | ctx.beginPath(); 320 | ctx.rect(-barWidth/2, -barHeight/2, barWidth*(self.numInfectedFriends/self.numFriends), barHeight); 321 | ctx.fill(); 322 | } 323 | 324 | // a pointer for contagion level 325 | ctx.translate(0, -barHeight/2); 326 | ctx.save(); 327 | ctx.translate(barWidth*self.sim.contagion - barWidth/2, 0); 328 | ctx.lineCap = "butt"; 329 | ctx.strokeStyle = uiColor; 330 | ctx.lineWidth = 1.5; 331 | ctx.beginPath(); 332 | ctx.moveTo(0,-2); 333 | ctx.lineTo(0,barHeight+2); 334 | ctx.stroke(); 335 | ctx.restore(); 336 | 337 | ctx.restore(); 338 | 339 | } 340 | 341 | ctx.restore(); 342 | 343 | }; 344 | 345 | // Hit Test 346 | self.hitTest = function(x,y,buffer){ 347 | // ACTUALLY IGNORE BUFFER'S AMOUNT, IT'S TRUE OR FALSE. 348 | // if(buffer===undefined) buffer=0; 349 | buffer = !!buffer; 350 | var dx = self.x-x; 351 | var dy = self.y-y; 352 | var dist2 = dx*dx+dy*dy; 353 | 354 | var r = radius; 355 | var s; 356 | if(s = self.sim.options.scale) r*=s; 357 | 358 | r = buffer ? Math.max(r+10, 40) : r; 359 | 360 | return (dist2 div{ 49 | position: absolute; 50 | width: 100%; height: 100%; 51 | overflow: hidden; 52 | cursor: none; 53 | } 54 | #simulations, #slideshow{ 55 | position: absolute; 56 | width: 960px; 57 | height: 540px; 58 | margin: auto; 59 | top:0; left:0; right:0; bottom:0; 60 | 61 | -webkit-user-select: none; 62 | -moz-user-select: none; 63 | -ms-user-select: none; 64 | user-select: none; 65 | } 66 | #simulations canvas, #slideshow > div{ 67 | position: absolute; 68 | } 69 | #slideshow .box.image{ 70 | background-size: 100% 100%; 71 | } 72 | #slideshow .next_button{ 73 | /*display: inline-block;*/ 74 | margin: 0 auto; 75 | position: relative; 76 | top: -10px; 77 | width: 300px; 78 | height: 20px; 79 | padding: 37px 0 43px 0; 80 | background-image: url(../sprites/button_large.png); 81 | background-size: 100% auto; 82 | text-align: center; 83 | line-height: 25px; 84 | } 85 | #slideshow .next_button:hover{ 86 | background-position: 0 -100px; 87 | } 88 | #slideshow .next_button[disabled]{ 89 | pointer-events: none; 90 | opacity: 0.3; 91 | } 92 | .transitionable{ 93 | transition: opacity 0.3s ease-in-out, 94 | left 0.3s ease-in-out, 95 | top 0.3s ease-in-out; 96 | } 97 | 98 | #scratch{ 99 | position: absolute; 100 | cursor: none; 101 | display: none; 102 | pointer-events: none; 103 | width: 100%; height: 100%; 104 | } 105 | 106 | /* Skip */ 107 | #container > #skip{ 108 | 109 | display: none; 110 | 111 | position: absolute; 112 | right:10px; 113 | bottom:10px; 114 | width: 80px; 115 | height: 25px; 116 | font-size: 25px; 117 | line-height: 25px; 118 | color: #aaa; 119 | text-align: right; 120 | 121 | -webkit-user-select: none; 122 | -moz-user-select: none; 123 | -ms-user-select: none; 124 | user-select: none; 125 | 126 | } 127 | #container > #skip:hover{ 128 | color: #ccc; 129 | } 130 | 131 | /* Peep Icon */ 132 | .peep_icon{ 133 | height:1em; 134 | position: relative; 135 | top: 3px; 136 | transform: scale(1.2); 137 | } 138 | 139 | /* Right & Down Arrows */ 140 | .rarr, .darr{ 141 | display: inline-block; 142 | width: 1em; 143 | height: 1em; 144 | background: url(../sprites/ui/arrow.png); 145 | background-size: 100% auto; 146 | position: relative; 147 | top: 3px; 148 | } 149 | .darr{ 150 | transform: rotate(90deg); 151 | } 152 | 153 | /* Sim UI */ 154 | .sim_ui{ 155 | position: absolute; 156 | width: 200px; 157 | height: 100px; 158 | border: none !important; 159 | } 160 | .sim_ui > div{ 161 | position: absolute; 162 | color: #fff; 163 | text-align: center; 164 | border-radius: 10px; 165 | } 166 | .sim_ui > #start_button{ 167 | width: 200px; 168 | padding: 0.5em 0; 169 | background-image: url(../sprites/red_button.png); 170 | background-size: 100% auto; 171 | 172 | position: relative; 173 | top:0; 174 | transition: top 0.1s ease-in-out; 175 | } 176 | .sim_ui[active] > #start_button{ 177 | background-position: 0 -62.5px; 178 | } 179 | .sim_ui > #start_button:hover{ 180 | top:-3px; 181 | } 182 | .sim_ui > #start_button:active{ 183 | top:3px; 184 | } 185 | 186 | /* Sandbox UI */ 187 | .sandbox_ui{ 188 | width: 270px; 189 | } 190 | .sandbox_ui input[type="range"]{ 191 | width: 100%; 192 | cursor: none; 193 | } 194 | .choose_one{ 195 | overflow: hidden; 196 | } 197 | .choose_one > div{ 198 | float: left; 199 | margin: 3px; 200 | opacity: 0.25; 201 | } 202 | .choose_one > div[selected]{ 203 | opacity: 1; 204 | } 205 | .choose_color{ 206 | width: 40px; 207 | height: 40px; 208 | background: url(../sprites/peeps.png); 209 | background-size: auto 100%; 210 | transform: scale(1.2); 211 | } 212 | .choose_tool{ 213 | background: #fff; 214 | font-size: 16px; 215 | line-height: 16px; 216 | border: 1px solid black; 217 | padding: 3px; 218 | border-radius: 5px; 219 | } 220 | .choose_tool > #icon{ 221 | display: inline-block; 222 | width:16px; height:16px; 223 | background: url(../sprites/sandbox_tools.png); 224 | background-size: auto 100%; 225 | } 226 | #sandbox_shortcuts_label{ 227 | font-size: 22px; 228 | } 229 | #sandbox_shortcuts{ 230 | font-size: 20px; 231 | line-height: 1.2em; 232 | color: #999; 233 | } 234 | 235 | /* MODAL */ 236 | #modal_container{ 237 | top:100%; 238 | transition: top 0.4s ease-in-out; 239 | } 240 | #modal_container[show]{ 241 | top:0%; 242 | } 243 | #modal_bg{ 244 | width: 100%; 245 | height: 100%; 246 | } 247 | #modal{ 248 | 249 | position: absolute; 250 | margin: auto; 251 | top:0; left:0; right:0; bottom:0; 252 | 253 | background: #444; 254 | color: #fff; 255 | 256 | } 257 | #modal #modal_content > div:first-child > h3{ 258 | border-top: none; 259 | } 260 | #modal #modal_content > h3{ 261 | border-top: none; 262 | } 263 | #modal h3{ 264 | font-size: 1.3em; 265 | margin-bottom: 0.7em; 266 | padding-top: 0.7em; 267 | margin-top: 1em; 268 | border-top: 5px solid #282828; 269 | } 270 | #modal[size=small]{ 271 | width: 700px; 272 | height: 300px; 273 | } 274 | #modal[size=large]{ 275 | width: 800px; 276 | height: 540px; 277 | } 278 | #modal_close{ 279 | position: absolute; 280 | top: 0; 281 | right: 0; 282 | width: 40px; 283 | height: 40px; 284 | font-size: 50px; 285 | text-align: center; 286 | line-height: 25px; 287 | } 288 | #modal_content_container{ 289 | overflow: auto; 290 | width: 100%; height:100%; 291 | } 292 | #modal_content{ 293 | margin:1.5em; 294 | letter-spacing: 1px; 295 | } 296 | 297 | /* NAVIGATION */ 298 | #navigation_container{ 299 | position: absolute; 300 | bottom:0; 301 | background: #222; 302 | width: 100%; 303 | height:60px; 304 | 305 | -webkit-user-select: none; 306 | -moz-user-select: none; 307 | -ms-user-select: none; 308 | user-select: none; 309 | } 310 | #sound{ 311 | position: absolute; 312 | left:0; top:0; 313 | color: #fff; 314 | width: 150px; 315 | font-size: 30px; 316 | height: 60px; 317 | } 318 | #sound[mute=yes]{ 319 | opacity: 0.5; 320 | } 321 | #sound_icon{ 322 | background: url(../sprites/ui/sound.png); 323 | background-size: auto 100%; 324 | width: 60px; height: 60px; 325 | position: absolute; 326 | } 327 | #sound_on, #sound_off{ 328 | position: absolute; 329 | left:65px; 330 | padding: 15px 0; 331 | display: block; 332 | line-height: 28px; 333 | display: none; 334 | letter-spacing: 2px; 335 | } 336 | #sound[mute=no] > #sound_icon{ 337 | /*background: rgba(255,255,255,0.5);*/ 338 | background-position: 0px 0px; 339 | } 340 | #sound[mute=yes] > #sound_icon{ 341 | /*background: rgba(255,255,255,0.25);*/ 342 | background-position: -60px 0px; 343 | } 344 | #sound[mute=no] > #sound_on{ 345 | display: block; 346 | } 347 | #sound[mute=yes] > #sound_off{ 348 | display: block; 349 | } 350 | #sharing{ 351 | position: absolute; 352 | right:10px; top:0; 353 | width: 150px; 354 | overflow: hidden; 355 | } 356 | #sharing > a{ 357 | float: left; 358 | display: block; 359 | width: 50px; 360 | height: 60px; 361 | background: url(../sprites/ui/sharing.png); 362 | background-size: auto 100%; 363 | } 364 | #sharing #fb{ 365 | background-position: 0px 0px; 366 | } 367 | #sharing #tw{ 368 | background-position: -50px 0px; 369 | } 370 | #sharing #em{ 371 | background-position: -100px 0px; 372 | } 373 | #share_title{ 374 | display: none; 375 | } 376 | #share_desc{ 377 | display: none; 378 | } 379 | #translations{ 380 | position: absolute; 381 | top: 14px; 382 | left: calc(50% - 400px); 383 | width: 800px; 384 | text-align: center; 385 | color: #fff; 386 | font-size: 16px; 387 | line-height: 16px; 388 | letter-spacing: 0.5px; 389 | } 390 | #navigation{ 391 | 392 | display: none; 393 | 394 | position: absolute; 395 | top: 10px; 396 | left: calc(50% - 300px); 397 | width: 600px; 398 | text-align: center; 399 | } 400 | #navigation > div{ 401 | width: 35px; 402 | height: 35px; 403 | background: #222; 404 | color:#fff; 405 | border-radius: 20px; 406 | display: inline-block; 407 | border: 1px solid #fff; 408 | margin: 0 1px; 409 | text-align: center; 410 | overflow: hidden; 411 | line-height: 34px; 412 | position: relative; 413 | } 414 | #navigation > div[highlight]{ 415 | background: #fff; 416 | color: #222; 417 | } 418 | #navigation > div > span:nth-child(1){ 419 | display: block; 420 | position: absolute; 421 | width: 100%; 422 | } 423 | #navigation > div > span:nth-child(2){ 424 | display: none; 425 | } 426 | #navigation > div:hover{ 427 | background: rgba(255,255,255,0.25); 428 | } 429 | #navigation > div[highlight]:hover{ 430 | background: #fff; 431 | } 432 | #navigation > span.nav_divider{ 433 | width: 2px; 434 | height: 40px; 435 | background: rgba(255,255,255,0.2); 436 | border-radius: 20px; 437 | display: inline-block; 438 | margin: 0 8px; 439 | } 440 | #navigation > span#nav_bubble{ 441 | 442 | transition: opacity 0.2s ease-in-out, 443 | left 0.2s ease-in-out, 444 | top 0.2s ease-in-out; 445 | 446 | display: none; 447 | opacity: 0; 448 | 449 | position: absolute; 450 | top:-80px; 451 | left:0; 452 | 453 | background: rgba(0,0,0,0.8); 454 | color: #fff; 455 | text-align: center; 456 | border-radius: 20px; 457 | 458 | width: 220px; 459 | padding: 6px 0; 460 | 461 | } 462 | #navigation > span#nav_bubble:after{ 463 | top: 100%; 464 | left: 50%; 465 | border: solid transparent; 466 | content: " "; 467 | height: 0; 468 | width: 0; 469 | position: absolute; 470 | pointer-events: none; 471 | border-color: rgba(0, 0, 0, 0); 472 | border-top-color: rgba(0,0,0,0.8); 473 | border-width: 15px; 474 | margin-left: -15px; 475 | } 476 | 477 | /* PENCIL */ 478 | #pencil_container{ 479 | position: absolute; 480 | top:0; left:0; 481 | width: 100%; 482 | height: 100%; 483 | overflow: hidden; 484 | pointer-events: none; 485 | cursor: none; 486 | } 487 | #pencil{ 488 | position: absolute; 489 | width:100px; 490 | height:100px; 491 | pointer-events: none; 492 | cursor: none; 493 | } 494 | 495 | /* PRE-PRELOADER */ 496 | #pre_preloader{ 497 | position: absolute; 498 | background: #fff; 499 | width:100%; 500 | height: 100%; 501 | cursor: default; 502 | } 503 | #pre_preloader > div{ 504 | text-align: center; 505 | width:300px; height:40px; 506 | line-height: 40px; 507 | font-size: 40px; 508 | margin: auto; 509 | position: absolute; 510 | top:-40px; left:0; right:0; bottom:0; 511 | } 512 | 513 | /* THIS THING'S WORDS */ 514 | words, bonus, reference{ 515 | display: none; 516 | } 517 | 518 | /* BONUS BOX */ 519 | bon{ 520 | margin: 0.75em auto; 521 | display: block; 522 | 523 | background: #ccc; 524 | color: #444; 525 | text-align: left; 526 | 527 | width: 300px; 528 | height: 56px; 529 | padding: 23px 20px 17px 80px; 530 | border-bottom: 4px solid rgba(0,0,0,0.25); 531 | border-radius: 5px; 532 | 533 | line-height: 1.1em; 534 | background-size: 400px auto; 535 | 536 | position: relative; 537 | transition: top 0.1s ease-in-out; 538 | top:0; 539 | } 540 | bon:before{ 541 | content: ''; 542 | display: block; 543 | position: absolute; 544 | 545 | left: 25px; 546 | top: 14px; 547 | width: 35px; 548 | height: 70px; 549 | 550 | background: url(../sprites/ui/bonus.png); 551 | background-size: 100% 100%; 552 | } 553 | bon:hover{ 554 | top:-3px; 555 | } 556 | 557 | /* REFERENCES */ 558 | ref{ 559 | position: relative; 560 | display: inline-block; 561 | padding-left: 2px; 562 | width: 21px; 563 | } 564 | ref:before{ 565 | content: '*'; 566 | background: #ddd; 567 | color: #444; 568 | padding: 3px; 569 | width: 15px; 570 | height: 15px; 571 | display: block; 572 | line-height: 26px; 573 | border-radius: 20px; 574 | font-size: 30px; 575 | position: absolute; 576 | text-align: center; 577 | top: -25px; 578 | } 579 | ref:hover:before{ 580 | background: #eee; 581 | color: #999; 582 | } 583 | 584 | /* TO SEE LAYOUT */ 585 | /*.box, #simulations{ 586 | border: 1px solid #eee; 587 | }*/ 588 | 589 | /* A NICE CIRCLE */ 590 | /* Thanks to: https://skeate.github.io/2015/07/13/Wrapping-Text-to-Fit-Shaped-Containers-with-CSS.html */ 591 | .circle { 592 | /*background: #accede;*/ 593 | text-align: center; 594 | width: 540px; 595 | height: 540px; 596 | border-radius: 100%; 597 | } 598 | .circle::before { 599 | content: ''; 600 | height: 100%; 601 | width: 50%; 602 | float: left; 603 | shape-outside: polygon(0 0, 100% 0, 60% 4%, 40% 10%, 20% 20%, 10% 28.2%, 5% 34.4%, 0 50%, 5% 65.6%, 10% 71.8%, 20% 80%, 40% 90%, 60% 96%, 100% 100%, 0% 100%); 604 | } 605 | .circle > span::before { 606 | content: ''; 607 | height: 100%; 608 | width: 50%; 609 | float: right; 610 | shape-outside: polygon(100% 0, 0 0, 40% 4%, 60% 10%, 80% 20%, 90% 28.2%, 95% 34.4%, 100% 50%, 95% 65.6%, 90% 71.8%, 80% 80%, 60% 90%, 40% 96%, 0 100%, 100% 100%); 611 | } --------------------------------------------------------------------------------