diff --git a/css/index.css b/css/index.css
index 95f5f73..c8ff4cb 100644
--- a/css/index.css
+++ b/css/index.css
@@ -273,9 +273,9 @@ words, bonus, glossary{
}
/* TO SEE LAYOUT */
-/*.box, #simulations{
+.box, #simulations{
border: 1px solid #eee;
-}*/
+}
/* A NICE CIRCLE */
/* Thanks to: https://skeate.github.io/2015/07/13/Wrapping-Text-to-Fit-Shaped-Containers-with-CSS.html */
diff --git a/index.html b/index.html
index 1f66268..7866b15 100644
--- a/index.html
+++ b/index.html
@@ -184,64 +184,120 @@ let's play! →
-Let's draw a network!
-Each connection represents a friendship between two people:
+ Let's draw a network!
+ Each connection represents a friendship between two people:
-draw to connect
+ draw to connect
-scratch to disconnect
+ scratch to disconnect
-feel free to play around! when you're done,
-let's continue →
+
+ feel free to keep playing around, and draw whatever friendship network you want!
+ when you're done,
+ let's continue →
+
-blah blah blah blah
-blah blah blah blah
-blah blah blah blah
-
-blah blah blah blah
-blah blah blah blah
-thresholds NOT COUNTING THEMSELVES
+
+ But people don't just have social connections to make pretty pictures.
+ People look at their social connections, to understand their social world.
+ In this example, people look to their peers to
+ find out what % of their friends (not counting selves) are,
+ say, binge-drinkers. (img)
+
-
-# of drinker friends / # of total friends
+
+
+ Draw/erase connections, and see what happens! →
-
-% of friends are drinkers
-
-
-(black line shows the 50% "majority" mark)
+
+
+ top-left:
+ # of drinker friends / # of total friends
+
+ top-right:
+ % of drinker friends →
+
+ black line:
+ the 50% "majority" threshold
+
(they'll glow if past threshold)
+
-and next...
+ cool, got it
-blah blah drinking
-blah blah next
+
+ However, networks can fool people.
+ Just like how you see the earth as flat because you're on it,
+ people get wrong ideas about society because they're in it.
+
+
+
+ (BONUS BOX: OTHER CONNECTIONS)
+
+
+
+ For example, a 1991 study(*) showed that
+ “virtually all [college] students reported that their friends drank more than they did.”
+ But that seems impossible!
+ How can that be?
+ Well, you're about to invent the answer yourself, by drawing a network.
+ It's time to...
+
+ FOOL EVERYONE →
+
-blah blah puzzle
+
+ PUZZLE TIME!
+
+ Fool everyone into thinking
+ the majority of their friends are binge-drinkers (img)
+ (even though binge-drinkers are outnumbered 2-to-1)
+
-HOW MANY PEEPS FOOLED:
+ FOOLED:
+
+
+ out of 9 people
-blah blah puzzle
-a winrar is you
+ Congrats! You manipulated a group of students into believing
+ in the prevalance of an incredibly unhealthy social norm! Good going!
+ ...uh. thanks?
-blah blah post-puzzle
-simple contagion...
+
+ What you just created is called The Majority Illusion(*),
+ which also explains why people think their political views are consensus,
+ or why extremism seems more common than it actually is.
+ Madness.
+
+
+
+ But ideas/behaviors aren't just passively observed, they actively spread.
+ So now, let's look at something network scientists call...
+
+ “Simple Contagion!” →
+
+ ← bonus challenge: make everyone think
+ less than half of their friends are binge-drinkers
+
+
+
+ 🙌 yay you did it 🙌
@@ -333,19 +389,19 @@ Select a tool...
-Draw Connections
+Draw Network
-Add Peep
+Add Person
Add "Infected"
-Move Peep
+Move Person
-Delete Peep
+Delete Person
CLEAR IT ALL
@@ -355,13 +411,13 @@ Delete Peep
(...or, use keyboard shortcuts!)
-[1]: Add Peep
+[1]: Add Person
-[2]: Add "Infected" Peep
+[2]: Add "Infected" Person
-[Space]: Move Peep
+[Space]: Move Person
-[Backspace]: Delete Peep
+[Backspace]: Delete Person
diff --git a/js/chapters/1_Networks.js b/js/chapters/1_Networks.js
index 0b9e7b5..d3ebfda 100644
--- a/js/chapters/1_Networks.js
+++ b/js/chapters/1_Networks.js
@@ -22,8 +22,8 @@ SLIDES.push(
fullscreen: true,
network: {
"contagion":0,
- "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],[539,375,0],[216,299,0],[107,311,0],[-61,220,0],[87,452,0],[733,147,0],[760,293,0],[753,448,0],[744,46,0],[134,33,0],[929,181,0],[848,111,0],[1013,330,0],[880,269,0],[538,128,0],[208,391,0],[853,356,0]],
- "connections":[[5,6]]
+ "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]],
+ "connections":[[5,6,0]]
}
},
@@ -55,7 +55,7 @@ SLIDES.push(
{
type:"box",
id:"end_words",
- text:"_1_tutorial_end", x:230, y:425, w:500, h:70, align:"center",
+ text:"_1_tutorial_end", x:230, y:400, w:500, h:70, align:"center",
hidden:true
}
@@ -110,23 +110,38 @@ SLIDES.push(
{
type:"box",
id:"_1_threshold",
- text:"_1_threshold", x:80, y:25, w:300
+ text:"_1_threshold", x:60, y:25, w:400
+ },
+ {
+ type:"box",
+ id:"_1_threshold_instruction",
+ text:"_1_threshold_instruction", x:110, y:260, w:300,
+ align:"center"
+ },
+ {
+ type:"box",
+ id:"_1_threshold_explanation",
+ text:"_1_threshold_explanation", x:105, y:340, w:400,
+ align:"right",
+ color:"#bbb",
+ fontSize:"0.75em",
+ lineHeight:"1.2em"
},
{
type:"box",
id:"_1_threshold_end",
- text:"_1_threshold_end", x:80, y:400, w:300
+ text:"_1_threshold_end", x:60, y:430, w:400
},
// SIMULATION: THRESHOLD
{
type:"sim",
- x:400, y:70,
+ x:420, y:70,
fullscreen: true,
network: {
"contagion":0.5,
- "peeps":[[95,65,0],[417,380,1],[52,340,0],[399,92,1]],
- "connections":[[2,3],[3,1]],
+ "peeps":[[141,99,0],[444,373,1],[442,103,1],[144,371,0]],
+ "connections":[[2,1,0],[3,2,0]]
},
options:{
infectedFrame: 2,
@@ -141,13 +156,15 @@ SLIDES.push(
{
remove:[
{ type:"box", id:"_1_threshold" },
+ { type:"box", id:"_1_threshold_instruction" },
+ { type:"box", id:"_1_threshold_explanation" },
{ type:"box", id:"_1_threshold_end" }
],
add:[
{
type:"box",
id:"_1_pre_puzzle",
- text:"_1_pre_puzzle", x:80, y:25, w:325, h:540
+ text:"_1_pre_puzzle", x:60, y:0, w:400
}
]
},
@@ -165,7 +182,7 @@ SLIDES.push(
{
id:"puzzle",
type:"sim",
- x:480-250, y:25,
+ x:410, y:25,
fullscreen: true,
network: {
"contagion":0.5,
@@ -179,31 +196,80 @@ SLIDES.push(
},
// Done? Let's go... (hidden at first...)
+ {
+ type:"box",
+ id:"_1_puzzle",
+ text:"_1_puzzle", x:60, y:10, w:300
+ },
+ {
+ type:"box",
+ id:"_1_puzzle_metric",
+ text:"_1_puzzle_metric", x:60, y:220, w:300
+ },
{
type:"box",
id:"_1_puzzle_end",
- text:"_1_puzzle_end", x:680, y:430, w:300, align:"center",
+ text:"_1_puzzle_end", x:60, y:220, w:300,
hidden:true
}
],
+ onstart:function(slideshow, state){
+
+ // Modify puzzle metric box
+ var metric = slideshow.boxes.getChildByID("_1_puzzle_metric");
+ metric.innerHTML = "";
+
+ var COLOR = "hsl(50, 100%, 50%)";
+
+ // label
+ var label = document.createElement("div");
+ metric.appendChild(label);
+ label.style.color = COLOR;
+
+ // bar
+ var bar_container = document.createElement("div");
+ metric.appendChild(bar_container);
+ bar_container.style.border = "2px solid "+COLOR;
+ bar_container.style.width = "100%";
+ bar_container.style.height = "1em";
+ bar_container.style.position = "relative";
+ var bar = document.createElement("div");
+ bar_container.appendChild(bar);
+ bar.style.background = COLOR;
+ bar.style.height = "100%";
+ bar.style.position = "absolute";
+
+ // Save this cool DOM into state
+ state.metric_label = label;
+ state.metric_bar = bar;
+
+ },
+
onupdate:function(slideshow, state){
+ // How many peeps?
+ var sim = slideshow.simulations.sims[0];
+ var peepCount = 0;
+ sim.peeps.forEach(function(peep){
+ if(peep.isPastThreshold) peepCount++;
+ });
+
+ // Modify metric box!
+ var label = getWords("_1_puzzle_metric") + " " + peepCount + " " + getWords("_1_puzzle_metric_2");
+ state.metric_label.innerHTML = label;
+ state.metric_bar.style.width = Math.round((peepCount/9)*100)+"%";
+
// Win only if EVERYONE hits threshold
if(!state.won){
-
- var sim = slideshow.simulations.sims[0];
- var peepCount = 0;
- sim.peeps.forEach(function(peep){
- if(peep.isPastThreshold) peepCount++;
- });
if(peepCount==9){
+ var boxes = slideshow.boxes;
state.won = true;
- slideshow.boxes.showChildByID("_1_puzzle_end");
+ boxes.hideChildByID("_1_puzzle_metric");
+ boxes.showChildByID("_1_puzzle_end");
sim.win();
}
-
}
}
@@ -213,20 +279,50 @@ SLIDES.push(
// post-puzzle ramble, introduce simple contagion
{
remove:[
+ { type:"box", id:"_1_puzzle" },
+ { type:"box", id:"_1_puzzle_metric" },
{ type:"box", id:"_1_puzzle_end" }
],
move:[
// shift sim to side
- {type:"sim", id:"puzzle", x:0}
+ {type:"sim", id:"puzzle", x:20}
],
add:[
// new text
{
type:"box",
id:"_1_post_puzzle",
- text:"_1_post_puzzle", x:600, y:0, w:300
+ text:"_1_post_puzzle", x:560, y:0, w:400
+ },
+ {
+ type:"box",
+ id:"_1_post_puzzle_bonus",
+ text:"_1_post_puzzle_bonus", x:170, y:1000 // offscreen!
+ },
+ ],
+
+ onupdate:function(slideshow, state){
+
+ // How many peeps passed?
+ var sim = slideshow.simulations.sims[0];
+ var peepCount = 0;
+ sim.peeps.forEach(function(peep){
+ if(peep.numFriends>0 && !peep.isPastThreshold) peepCount++;
+ });
+
+ // Win Bonus
+ if(!state.won){
+ if(peepCount==9){
+ var winbox = slideshow.boxes.getChildByID("_1_post_puzzle_bonus");
+ if(winbox){
+ winbox.style.top = "270px";
+ state.won = true;
+ }
+ }
}
- ]
+
+ }
+
}
);
\ No newline at end of file
diff --git a/js/lib/helpers.js b/js/lib/helpers.js
index d22bc33..e34d18d 100644
--- a/js/lib/helpers.js
+++ b/js/lib/helpers.js
@@ -72,7 +72,7 @@ function fadeOut(container, dom){
}
// Tween position
-function tweenPosition(from, to){
+function tweenPosition(from, to, callback){
var x1 = from.x;
var y1 = from.y;
var x2 = to.x;
@@ -95,8 +95,25 @@ function tweenPosition(from, to){
from.x = x1 + dx*easeInOutSine(t);
from.y = y1 + dy*easeInOutSine(t);
+ // Callback
+ if(callback){
+ callback(from);
+ }
+
});
}
+/*function tweenBox(box, to){
+ var from = {
+ x: parseInt(box.style.left),
+ y: parseInt(box.style.top)
+ };
+ to.x = (to.x===undefined) ? from.x : to.x;
+ to.y = (to.y===undefined) ? from.y : to.y;
+ tweenPosition(from, to, function(position){
+ box.style.left = position.x + "px";
+ box.style.top = position.y + "px";
+ });
+}*/
// From Robert Penner: http://robertpenner.com/scripts/easing_equations.txt
function easeInOutSine(t) {
return -1/2 * (Math.cos((Math.TAU/2)*t) - 1);
diff --git a/js/main.js b/js/main.js
index 0573dee..596e7f8 100644
--- a/js/main.js
+++ b/js/main.js
@@ -29,6 +29,6 @@ window.onload = function(){
window.requestAnimationFrame(update);
// First slide!
- slideshow.gotoChapter("Networks");
+ slideshow.gotoChapter("Networks-Majority");
}
\ No newline at end of file
diff --git a/js/sim/Peep.js b/js/sim/Peep.js
index 7f939b3..28134b6 100644
--- a/js/sim/Peep.js
+++ b/js/sim/Peep.js
@@ -152,7 +152,7 @@ function Peep(config){
// Draw
var radius = 25;
- var barWidth = radius*1.75;
+ var barWidth = radius*2;
var barHeight = 10;
var bodyRotation = Math.TAU*Math.random();
var PEEP_COLORS = [
@@ -214,17 +214,25 @@ function Peep(config){
// Say: Infected/Friends (% then n/n)
ctx.translate(0,-43);
- ctx.font = '10px FuturaHandwritten';
+ ctx.font = '9px FuturaHandwritten';
ctx.fillStyle = uiColor;
ctx.textBaseline = "middle";
ctx.fontWeight = "bold";
- ctx.textAlign = "center";
if(self.numFriends>0){
+
+ // #
+ ctx.textAlign = "left";
var labelNum = self.numInfectedFriends+"/"+self.numFriends;
+ ctx.fillText(labelNum, -barWidth/2, 0);
+
+ // %
+ ctx.textAlign = "right";
var labelPercent = Math.round(100*(self.numInfectedFriends/self.numFriends)) + "%";
- var label = labelNum + "=" + labelPercent;
- ctx.fillText(label, 0, 0);
+ ctx.fillText(labelPercent, barWidth/2, 0);
+
+
}else{
+ ctx.textAlign = "center";
ctx.fillText("∅", 0, -1);
}
diff --git a/js/sim/Simulations.js b/js/sim/Simulations.js
index 8757af1..06ac02c 100644
--- a/js/sim/Simulations.js
+++ b/js/sim/Simulations.js
@@ -351,7 +351,7 @@ function Sim(config){
frame: frame,
spinSpeed: spinSpeed,
spin: Math.random()*Math.TAU,
- g: 0.05+Math.random()*0.10
+ g: 0.10+Math.random()*0.10
};
self.confetti.push(confetti);
}
diff --git a/js/slideshow/Boxes.js b/js/slideshow/Boxes.js
index 53879af..f4a0d21 100644
--- a/js/slideshow/Boxes.js
+++ b/js/slideshow/Boxes.js
@@ -53,6 +53,8 @@ function Boxes(){
box.innerHTML = getWords(config.text);
if(config.align) box.style.textAlign = config.align;
if(config.color) box.style.color = config.color;
+ if(config.fontSize) box.style.fontSize = config.fontSize;
+ if(config.lineHeight) box.style.lineHeight = config.lineHeight;
}
// pics:
diff --git a/js/slideshow/Slideshow.js b/js/slideshow/Slideshow.js
index d6ab500..81f6347 100644
--- a/js/slideshow/Slideshow.js
+++ b/js/slideshow/Slideshow.js
@@ -72,7 +72,8 @@ function Slideshow(){
slide.move.forEach(function(childConfig){
switch(childConfig.type){
case "box":
- //self.boxes.add(childConfig);
+ //var box = self.boxes.getChildByID(childConfig.id);
+ //tweenBox(box, childConfig);
break;
case "sim":
var sim = self.simulations.getChildByID(childConfig.id);