a whole buncha stuff

This commit is contained in:
Nicky Case 2018-04-02 13:43:20 -04:00
parent fd39f09979
commit ebc3c3046f
13 changed files with 492 additions and 66 deletions

View File

@ -13,14 +13,21 @@ body{
}
/* SIMULATION and SLIDESHOW */
#simulations_container, #slideshow_container{
#container{
position: absolute;
top:0; left:0;
width: 100%;
height: calc(100% - 60px);
}
#container > div{
position: absolute;
width: 100%; height: 100%;
overflow: hidden;
cursor: none;
}
#simulations{
border: 1px solid #eee;
}
#simulations, #slideshow{
position: absolute;
width: 960px;
@ -53,6 +60,21 @@ body{
#slideshow .next_button:hover{
background-position: 0 -100px;
}
.fadeable{
transition: opacity 0.3s ease-in-out;
}
#scratch{
display: none;
pointer-events: none;
background-image: url(sprites/scratch.png);
background-size: 200% 2000%;
background-position: 0% 0%;
}
/* MODAL */
#modal{
display: none;
}
/* NAVIGATION */
#navigation{

View File

@ -24,14 +24,24 @@ Cursor is allowed to flow EVERYWHERE though...
</head>
<body>
<!-- Simulation(s) in background -->
<div id="simulations_container">
<div id="simulations"></div>
</div>
<div id="container" class="fadeable">
<!-- Simulation(s) in background -->
<div id="simulations_container">
<div id="simulations"></div>
</div>
<!-- Slideshow: words & buttons -->
<div id="slideshow_container">
<div id="slideshow"></div>
</div>
<!-- Scratch Transition -->
<div id="scratch"></div>
<!-- Modal -->
<div id="modal"></div>
<!-- Slideshow: words & buttons -->
<div id="slideshow_container">
<div id="slideshow"></div>
</div>
<!-- Navigation: Audio, Contents, Share, Translations -->
@ -102,6 +112,7 @@ feel free to play around! when you're done,
blah blah blah blah
blah blah blah blah
blah blah blah blah
<span bonus="herp"></span>
blah blah blah blah
blah blah blah blah
thresholds NOT COUNTING THEMSELVES
@ -170,7 +181,11 @@ reset sim
<!-- BONUS BOXES (footnotes) -->
<!-- - - - - - - - - - - - - -->
<bonus>
<bonus id="herp">
<title>HERP DERP</title>
<description>
Herp derp HERP derp derp? Herp derp DERP herp herp derp!
</description>
</bonus>
<!-- - - - - - -->
@ -193,6 +208,7 @@ reset sim
<script src="js/slideshow/Slideshow.js"></script>
<script src="js/slideshow/Pencil.js"></script>
<script src="js/slideshow/Boxes.js"></script>
<script src="js/slideshow/Scratch.js"></script>
<script src="js/sim/Peep.js"></script>
<script src="js/sim/Connection.js"></script>

View File

@ -182,11 +182,32 @@ SLIDES.push(
{
type:"box",
id:"_1_puzzle_end",
text:"_1_puzzle_end", x:680, y:430, w:300, align:"center"
//hidden:true
text:"_1_puzzle_end", x:680, y:430, w:300, align:"center",
hidden:true
}
]
],
// Logic to fade in/out words & stuff
onupdate:function(slideshow, state){
// 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){
state.won = true;
slideshow.boxes.showChildByID("_1_puzzle_end");
sim.win();
}
}
}
},

View File

@ -1,7 +1,61 @@
// 0 - INTRODUCTION
// 2 - Simple Contagion
// Puzzles for re-use in Complex Contagion...
var CONTAGION_PUZZLE = {
"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]],
"connections":[[0,1],[1,3],[3,2],[3,7],[7,8],[8,6],[6,4],[4,2],[6,5],[5,9]]
};
var CASCADE_PUZZLE = {
"peeps":[[34,63,1],[171,97,0],[311,179,0],[191,240,0],[309,312,0],[542,77,0],[450,164,0],[528,264,0],[654,229,0],[661,117,0],[869,295,0],[720,337,0],[926,428,0],[845,508,0],[706,464,0]],
"connections":[[0,1],[3,2],[2,4],[4,3],[6,7],[7,8],[8,9],[9,5],[5,6],[6,9],[9,7],[7,5],[5,8],[8,6],[11,10],[11,14],[14,13],[13,12],[12,10],[11,12],[12,14],[14,10],[10,13],[13,11]]
};
SLIDES.push(
{
chapter: "Simple",
clear:true
}
clear:true,
add:[
// Lil' contagion
{
type:"sim",
x:0, y:80,
fullscreen: true,
network: {
"contagion":0,
"peeps":CONTAGION_PUZZLE.peeps,
"connections":CONTAGION_PUZZLE.connections
},
options:{
infectedFrame: 1,
scale: 1.25
}
},
]
},
{
chapter: "Simple-Cascade",
clear:true,
add:[
// Lil' contagion
{
type:"sim",
x:0, y:0,
fullscreen: true,
network: {
"contagion":0,
"peeps":CASCADE_PUZZLE.peeps,
"connections":CASCADE_PUZZLE.connections
},
options:{
infectedFrame: 1,
scale: 1.25,
startUncuttable: true
}
},
]
},
);

View File

@ -1,6 +1,52 @@
// 0 - INTRODUCTION
// 3 - Complex Contagion
SLIDES.push(
{
chapter: "Complex"
}
chapter: "Complex",
clear:true,
add:[
// Lil' contagion
{
type:"sim",
x:0, y:80,
fullscreen: true,
network: {
"contagion":0.25,
"peeps":CONTAGION_PUZZLE.peeps,
"connections":CONTAGION_PUZZLE.connections
},
options:{
infectedFrame: 3,
scale: 1.25,
startUncuttable: true
}
},
]
},
{
chapter: "Complex-Cascade",
clear:true,
add:[
// Lil' contagion
{
type:"sim",
x:0, y:0,
fullscreen: true,
network: {
"contagion":0,
"peeps":CASCADE_PUZZLE.peeps,
"connections":CASCADE_PUZZLE.connections
},
options:{
infectedFrame: 3,
scale: 1.25,
startUncuttable: true
}
},
]
},
);

View File

@ -52,3 +52,71 @@ function removeFromArray(array, item){
var index = array.indexOf(item);
if(index>=0) array.splice(index,1);
}
// Fade In
function fadeIn(container, dom){
dom.style.opacity = 0;
dom.classList.add("fadeable");
container.appendChild(dom);
setTimeout(function(){
dom.style.opacity = 1;
},50);
}
function fadeOut(container, dom){
dom.classList.add("fadeable");
dom.style.opacity = 0;
setTimeout(function(){
container.removeChild(dom);
},300);
}
// Tween position
function tweenPosition(from, to){
var x1 = from.x;
var y1 = from.y;
var x2 = to.x;
var y2 = to.y;
var dx = x2-x1;
var dy = y2-y1;
var t = 0;
var handle = subscribe("update", function(){
// Time
t += 3/60;
if(t>=1){
from.x = x2;
from.y = y2;
unsubscribe(handle);
return;
}
// Update
from.x = x1 + dx*easeInOutSine(t);
from.y = y1 + dy*easeInOutSine(t);
});
}
// From Robert Penner: http://robertpenner.com/scripts/easing_equations.txt
function easeInOutSine(t) {
return -1/2 * (Math.cos((Math.TAU/2)*t) - 1);
};
// Get Bounding Box of points
function getBoundsOfPoints(points){
var minX=Infinity, minY=Infinity,
maxX=-Infinity, maxY=-Infinity;
points.forEach(function(p){
if(p.x<minX) minX=p.x;
if(p.y<minY) minY=p.y;
if(maxX<p.x) maxX=p.x;
if(maxY<p.y) maxY=p.y;
});
return {
x: minX,
y: minY,
width: maxX-minX,
height: maxY-minY,
};
}

View File

@ -18,6 +18,9 @@ window.onload = function(){
// Draw
slideshow.draw();
pencil.draw();
// Update
publish("update");
window.requestAnimationFrame(update);
@ -25,6 +28,6 @@ window.onload = function(){
window.requestAnimationFrame(update);
// First slide!
slideshow.gotoChapter("Networks");
slideshow.gotoChapter("Complex");
}

View File

@ -11,6 +11,7 @@ function Peep(config){
// Update:
self.numFriends = 0;
self.numInfectedFriends = 0;
self.isPastThreshold = false;
self.faceX = 0;
self.faceY = 0;
self.faceBlink = 0;

View File

@ -114,7 +114,11 @@ function Sim(config){
to = self.peeps[c[1]];
self.addConnection(from, to, false);
});
// todo: "start uncuttable"
if(self.options.startUncuttable){
self.connections.forEach(function(c){
c.uncuttable = true;
});
}
// Contagion
self.contagion = self.networkConfig.contagion;
@ -159,6 +163,26 @@ function Sim(config){
_draggingPeep.y = self.mouse.y+_draggingOffset.y;
}
// update confetti & winword...
self.confetti.forEach(function(confetti){
confetti.x += confetti.vx;
confetti.y += confetti.vy;
confetti.spin += confetti.spinSpeed;
confetti.vy += confetti.g;
confetti.vx *= 0.95;
confetti.vy *= 0.95;
});
if(self.winWord.ticker>=0){
self.winWord.ticker += 1/60;
if(self.winWord.ticker>5){
self.winWord.ticker = -1;
}
}
// On update! (for arbitrary sim-specific logic)
self.onupdate(self);
@ -190,6 +214,50 @@ function Sim(config){
ctx.restore();
// Draw confetti - NOT AFFECTED BY TRANSFORMS.
ctx.fillStyle = "#dd4040";
self.confetti.forEach(function(confetti){
ctx.save();
var offsetX = -Math.sin(confetti.spin)*9;
ctx.translate(confetti.x+offsetX, confetti.y);
ctx.rotate(Math.sin(confetti.spin)*0.2);
ctx.beginPath();
ctx.rect(-20,-10,40,20);
ctx.fill();
ctx.restore();
});
// Draw WIN WORD
if(self.winWord.ticker>=0){
ctx.save();
ctx.translate(self.winWord.x, self.winWord.y);
ctx.scale(2,2); // retina
// expand
if(self.winWord.ticker<0.2){
var scale = self.winWord.ticker/0.2;
ctx.scale(scale,scale);
}
// fade away
if(self.winWord.ticker>4){
var alpha = -(self.winWord.ticker-5);
ctx.globalAlpha = alpha;
}
ctx.font = '80px FuturaHandwritten';
ctx.fillStyle = "#000";
ctx.textBaseline = "middle";
ctx.fontWeight = "bold";
ctx.textAlign = "center";
var label = getWords("WIN");
ctx.fillText(label, 0, 0);
ctx.restore();
}
};
// Kill
@ -197,6 +265,57 @@ function Sim(config){
self.clear();
};
///////////////////
// WINNER WINNER //
///////////////////
self.wonBefore = false;
self.confetti = [];
self.winWord = {x:0, y:0, ticker:-1};
self.win = function(){
// ONLY ONCE
if(self.wonBefore) return;
self.wonBefore = true;
// Get center of peeps
var fullscreenOffsetX = config.x + simOffset.x;
var fullscreenOffsetY = config.y + simOffset.y;
var bounds = getBoundsOfPoints(self.peeps);
var cx = bounds.x + bounds.width/2;
var cy = bounds.y + bounds.height/2;
cx += fullscreenOffsetX;
cy += fullscreenOffsetY;
cx *= 2; // retina
cy *= 2; // retina
// Place Win Word
self.winWord.x = cx;
self.winWord.y = cy;
self.winWord.ticker = 0;
// Place confetti
for(var i=0; i<100; i++){
var angle = Math.random()*Math.TAU;
var burst = bounds.width/15;
var frame = Math.floor(Math.random()*5);
var spinSpeed = 0.03+Math.random()*0.03;
var confetti = {
x: cx,
y: cy,
vx: Math.cos(angle)*Math.random()*burst,
vy: Math.sin(angle)*Math.random()*burst - burst*0.25,
frame: frame,
spinSpeed: spinSpeed,
spin: Math.random()*Math.TAU,
g: 0.05+Math.random()*0.10
};
self.confetti.push(confetti);
}
};
///////////////////////////////
// secret keyboard interface //
///////////////////////////////
@ -252,7 +371,7 @@ function Sim(config){
return '{\n'+
'\t"contagion":'+savedNetwork.contagion+",\n"+
'\t"peeps":'+JSON.stringify(savedNetwork.peeps)+",\n"+
'\t"connections":'+JSON.stringify(savedNetwork.connections)+",\n"+
'\t"connections":'+JSON.stringify(savedNetwork.connections)+"\n"+
'}';
};

View File

@ -20,12 +20,16 @@ function Boxes(){
};
// Add Box
self.add = function(config){
self.add = function(config, withFade){
// Add to DOM
var box = document.createElement("div");
box.className = "box";
self.dom.appendChild(box);
if(!withFade){
self.dom.appendChild(box);
}else{
fadeIn(self.dom, box);
}
// Standard box properties...
if(config.id) box.id = config.id;
@ -65,6 +69,9 @@ function Boxes(){
}
// Replace bonus boxes...
// TODO
// Add to array
self.boxes.push(box);
@ -91,10 +98,16 @@ function Boxes(){
var toHide = self.getChildByID(id);
toHide.style.display = "none";
};
self.removeChildByID = function(id){
self.removeChildByID = function(id, withFade){
var removeBox = self.getChildByID(id);
self.dom.removeChild(removeBox);
if(!withFade){
self.dom.removeChild(removeBox);
}else{
fadeOut(self.dom, removeBox);
}
removeFromArray(self.boxes, removeBox);
};
}

View File

@ -0,0 +1,32 @@
function Scratch(){
var self = this;
self.dom = $("#scratch");
self.scratchIn = function(){
self.startUpdateLoop(false, function(){
self.dom.style.display = "none";
});
};
self.scratchOut = function(){
self.dom.style.display = "block";
self.startUpdateLoop(true);
};
self.startUpdateLoop = function(out, callback){
var frame = 0;
var xOffset = out ? 0 : -100;
var handle = subscribe("update", function(){
var yOffset = Math.floor(frame)*(-100);
self.dom.style.backgroundPosition = xOffset+"% "+yOffset+"%";
if(frame>19){
unsubscribe(handle);
if(callback) callback();
return;
}
frame+=0.5;
});
};
}

View File

@ -21,62 +21,93 @@ function Slideshow(){
// My stuff...
self.boxes = new Boxes();
self.simulations = new Simulations();
self.scratch = new Scratch();
// GOTO and NEXT
var _delay = 300;
self.goto = function(index){
self.slideIndex = index;
var isFirstSlide = (self.currentSlide==null);
self.currentSlide = SLIDES[self.slideIndex];
var slide = self.currentSlide;
// Clear?
if(slide.clear) self.clear();
var _delayNewSlide = 0;
if(slide.clear && !isFirstSlide){
_delayNewSlide = 700;
self.scratch.scratchOut(); // Scratch out
}
// Remove stuff
slide.remove = slide.remove || [];
slide.remove.forEach(function(childConfig){
switch(childConfig.type){
case "box":
self.boxes.removeChildByID(childConfig.id);
break;
case "sim":
//self.simulations.removeChildByID(childConfig);
break;
_setTimeout(function(){
// Scratch in?
if(_delayNewSlide>0){
self.clear();
self.scratch.scratchIn(); // Scratch in
}
});
// Move stuff
slide.move = slide.move || [];
slide.move.forEach(function(childConfig){
switch(childConfig.type){
case "box":
//self.boxes.add(childConfig);
break;
case "sim":
var sim = self.simulations.getChildByID(childConfig.id);
sim.config.x = (childConfig.x===undefined) ? sim.config.x : childConfig.x;
sim.config.y = (childConfig.y===undefined) ? sim.config.y : childConfig.y;
break;
}
});
// Remove stuff
slide.remove = slide.remove || [];
slide.remove.forEach(function(childConfig){
var withFade = true;
switch(childConfig.type){
case "box":
self.boxes.removeChildByID(childConfig.id, withFade);
break;
case "sim":
//self.simulations.removeChildByID(childConfig);
break;
}
});
// Add stuff
slide.add = slide.add || [];
slide.add.forEach(function(childConfig){
switch(childConfig.type){
case "box":
self.boxes.add(childConfig);
break;
case "sim":
self.simulations.add(childConfig);
break;
}
});
// Move stuff
slide.move = slide.move || [];
slide.move.forEach(function(childConfig){
switch(childConfig.type){
case "box":
//self.boxes.add(childConfig);
break;
case "sim":
var sim = self.simulations.getChildByID(childConfig.id);
var newPosition = {
x: (childConfig.x===undefined) ? sim.config.x : childConfig.x,
y: (childConfig.y===undefined) ? sim.config.y : childConfig.y
};
tweenPosition(sim.config, newPosition);
break;
}
});
// On start (if any)
self.currentState = {};
if(slide.onstart) slide.onstart(self, self.currentState);
// Add stuff
slide.add = slide.add || [];
var _delayAdd = ((slide.remove.length + slide.move.length)>0) ? _delay : 0;
_setTimeout(function(){
var withFade = ((slide.remove.length + slide.move.length)>0);
slide.add.forEach(function(childConfig){
switch(childConfig.type){
case "box":
self.boxes.add(childConfig, withFade);
break;
case "sim":
self.simulations.add(childConfig, withFade);
break;
}
})
}, _delayAdd);
// On start (if any)
self.currentState = {};
if(slide.onstart) slide.onstart(self, self.currentState);
}, _delayNewSlide);
};
var _setTimeout = function(callback, delay){
if(delay==0) return callback();
else setTimeout(callback, delay);
};
self.gotoChapter = function(chapterID){
var index = SLIDES.findIndex(function(slide){

BIN
slides/sprites/scratch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 KiB