Skip to content

Instantly share code, notes, and snippets.

@mikkoh
Created March 26, 2015 03:27
Show Gist options
  • Save mikkoh/72314695c8e1d348dd5f to your computer and use it in GitHub Desktop.
Save mikkoh/72314695c8e1d348dd5f to your computer and use it in GitHub Desktop.
functional particles
var rafLoop = require('raf-loop');
var COUNT_PARTICLE = 100;
var MAX_VELOCITY = 5;
var FRICTION_MAGNITUDE = 0.07;
var els = array(COUNT_PARTICLE, createElement);
var positions = create(COUNT_PARTICLE, [window.innerWidth * 0.5, window.innerHeight * 0.5, 0]);
var velocities = create(COUNT_PARTICLE, [rand(-MAX_VELOCITY, MAX_VELOCITY), rand(-MAX_VELOCITY, MAX_VELOCITY), rand(-MAX_VELOCITY, MAX_VELOCITY)]);
rafLoop( function(dt) {
var timeScale = dt / 16.6667;
var magnitudesVelocity = velocities.map(magnitude);
var unitVelocities = velocities.map(normalizeFromMagnitudes(magnitudesVelocity));
var magnitudesUnitVelocity = unitVelocities.map(magnitude);
var friction = unitVelocities.map(multiplyScalar(-FRICTION_MAGNITUDE));
// set friction to be -velocity of magnitudesVelocity < magnitudesUnitVelocity
friction = friction.map( function(vector, vectorIdx) {
var magVelocity = magnitudesVelocity[ vectorIdx ];
var magUnitVelocity = magnitudesUnitVelocity[ vectorIdx ];
// this is the point when friction should become 0
if( magVelocity < magUnitVelocity ) {
// set friction to be 0
return vector.map( function(value, valueIDX) {
return -velocities[ vectorIdx ][ valueIDX ];
});
} else {
return vector;
}
});
velocities = velocities.map(add(friction));
positions = positions.map(add(velocities));
els.forEach(updatePosition);
}).start();
function array(num, from) {
var rVal = [];
var i;
if(typeof from === 'function') {
for( i = 0; i < num; i++ ) {
rVal.push(from());
}
} else {
for( i = 0; i < num; i++ ) {
rVal.push(from);
}
}
return rVal;
}
function create(num, from) {
var rVal = [];
var vec;
var fromEach = function(from) {
if(typeof from === 'function') {
vec.push(from());
} else {
vec.push(from);
}
};
for( var i = 0; i < num; i++ ) {
vec = [];
rVal.push(vec);
from.forEach(fromEach);
}
return rVal;
}
function rand( min, max ) {
var maxMin = max - min;
return function() {
return Math.random() * maxMin + min;
};
}
function createElement() {
var el = document.createElement('div');
el.style.width = el.style.height = '5px';
el.style.background = '#BABEEE';
el.style.position = 'absolute';
el.style.left = el.style.top = 0;
document.body.appendChild(el);
return el;
}
function updatePosition(el, idx) {
el.style.transform = 'perspective(1000px) translate3d(' + positions[ idx ].join('px, ') + 'px)';
}
function add(vectorsToAdd) {
return function(vector, idxVector) {
return vector.map(function(value, idxValue) {
return value + vectorsToAdd[idxVector][idxValue];
});
};
}
function multiplyScalar(scalar) {
return function(vector) {
return vector.map(function(value) {
return value * scalar;
});
};
}
function normalize(vector) {
var mag = magnitude(vector);
return vector.map( function(value) {
return value / mag;
});
}
function normalizeFromMagnitudes(magnitudes) {
return function(vector, vectorIdx) {
var mag = magnitudes[vectorIdx];
return vector.map( function(value) {
return value / mag;
});
};
}
function magnitude(vector) {
var total = 0;
vector.forEach(function(value) {
total += value * value;
});
return Math.sqrt(total);
}
require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){function EventEmitter(){this._events=this._events||{};this._maxListeners=this._maxListeners||undefined}module.exports=EventEmitter;EventEmitter.EventEmitter=EventEmitter;EventEmitter.prototype._events=undefined;EventEmitter.prototype._maxListeners=undefined;EventEmitter.defaultMaxListeners=10;EventEmitter.prototype.setMaxListeners=function(n){if(!isNumber(n)||n<0||isNaN(n))throw TypeError("n must be a positive number");this._maxListeners=n;return this};EventEmitter.prototype.emit=function(type){var er,handler,len,args,i,listeners;if(!this._events)this._events={};if(type==="error"){if(!this._events.error||isObject(this._events.error)&&!this._events.error.length){er=arguments[1];if(er instanceof Error){throw er}throw TypeError('Uncaught, unspecified "error" event.')}}handler=this._events[type];if(isUndefined(handler))return false;if(isFunction(handler)){switch(arguments.length){case 1:handler.call(this);break;case 2:handler.call(this,arguments[1]);break;case 3:handler.call(this,arguments[1],arguments[2]);break;default:len=arguments.length;args=new Array(len-1);for(i=1;i<len;i++)args[i-1]=arguments[i];handler.apply(this,args)}}else if(isObject(handler)){len=arguments.length;args=new Array(len-1);for(i=1;i<len;i++)args[i-1]=arguments[i];listeners=handler.slice();len=listeners.length;for(i=0;i<len;i++)listeners[i].apply(this,args)}return true};EventEmitter.prototype.addListener=function(type,listener){var m;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events)this._events={};if(this._events.newListener)this.emit("newListener",type,isFunction(listener.listener)?listener.listener:listener);if(!this._events[type])this._events[type]=listener;else if(isObject(this._events[type]))this._events[type].push(listener);else this._events[type]=[this._events[type],listener];if(isObject(this._events[type])&&!this._events[type].warned){var m;if(!isUndefined(this._maxListeners)){m=this._maxListeners}else{m=EventEmitter.defaultMaxListeners}if(m&&m>0&&this._events[type].length>m){this._events[type].warned=true;console.error("(node) warning: possible EventEmitter memory "+"leak detected. %d listeners added. "+"Use emitter.setMaxListeners() to increase limit.",this._events[type].length);if(typeof console.trace==="function"){console.trace()}}}return this};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(type,listener){if(!isFunction(listener))throw TypeError("listener must be a function");var fired=false;function g(){this.removeListener(type,g);if(!fired){fired=true;listener.apply(this,arguments)}}g.listener=listener;this.on(type,g);return this};EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events||!this._events[type])return this;list=this._events[type];length=list.length;position=-1;if(list===listener||isFunction(list.listener)&&list.listener===listener){delete this._events[type];if(this._events.removeListener)this.emit("removeListener",type,listener)}else if(isObject(list)){for(i=length;i-->0;){if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}}if(position<0)return this;if(list.length===1){list.length=0;delete this._events[type]}else{list.splice(position,1)}if(this._events.removeListener)this.emit("removeListener",type,listener)}return this};EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[type])delete this._events[type];return this}if(arguments.length===0){for(key in this._events){if(key==="removeListener")continue;this.removeAllListeners(key)}this.removeAllListeners("removeListener");this._events={};return this}listeners=this._events[type];if(isFunction(listeners)){this.removeListener(type,listeners)}else{while(listeners.length)this.removeListener(type,listeners[listeners.length-1])}delete this._events[type];return this};EventEmitter.prototype.listeners=function(type){var ret;if(!this._events||!this._events[type])ret=[];else if(isFunction(this._events[type]))ret=[this._events[type]];else ret=this._events[type].slice();return ret};EventEmitter.listenerCount=function(emitter,type){var ret;if(!emitter._events||!emitter._events[type])ret=0;else if(isFunction(emitter._events[type]))ret=1;else ret=emitter._events[type].length;return ret};function isFunction(arg){return typeof arg==="function"}function isNumber(arg){return typeof arg==="number"}function isObject(arg){return typeof arg==="object"&&arg!==null}function isUndefined(arg){return arg===void 0}},{}],2:[function(require,module,exports){var process=module.exports={};process.nextTick=function(){var canSetImmediate=typeof window!=="undefined"&&window.setImmediate;var canMutationObserver=typeof window!=="undefined"&&window.MutationObserver;var canPost=typeof window!=="undefined"&&window.postMessage&&window.addEventListener;if(canSetImmediate){return function(f){return window.setImmediate(f)}}var queue=[];if(canMutationObserver){var hiddenDiv=document.createElement("div");var observer=new MutationObserver(function(){var queueList=queue.slice();queue.length=0;queueList.forEach(function(fn){fn()})});observer.observe(hiddenDiv,{attributes:true});return function nextTick(fn){if(!queue.length){hiddenDiv.setAttribute("yes","no")}queue.push(fn)}}if(canPost){window.addEventListener("message",function(ev){var source=ev.source;if((source===window||source===null)&&ev.data==="process-tick"){ev.stopPropagation();if(queue.length>0){var fn=queue.shift();fn()}}},true);return function nextTick(fn){queue.push(fn);window.postMessage("process-tick","*")}}return function nextTick(fn){setTimeout(fn,0)}}();process.title="browser";process.browser=true;process.env={};process.argv=[];function noop(){}process.on=noop;process.addListener=noop;process.once=noop;process.off=noop;process.removeListener=noop;process.removeAllListeners=noop;process.emit=noop;process.binding=function(name){throw new Error("process.binding is not supported")};process.cwd=function(){return"/"};process.chdir=function(dir){throw new Error("process.chdir is not supported")}},{}],3:[function(require,module,exports){if(typeof Object.create==="function"){module.exports=function inherits(ctor,superCtor){ctor.super_=superCtor;ctor.prototype=Object.create(superCtor.prototype,{constructor:{value:ctor,enumerable:false,writable:true,configurable:true}})}}else{module.exports=function inherits(ctor,superCtor){ctor.super_=superCtor;var TempCtor=function(){};TempCtor.prototype=superCtor.prototype;ctor.prototype=new TempCtor;ctor.prototype.constructor=ctor}}},{}],4:[function(require,module,exports){var now=require("performance-now"),global=typeof window==="undefined"?{}:window,vendors=["moz","webkit"],suffix="AnimationFrame",raf=global["request"+suffix],caf=global["cancel"+suffix]||global["cancelRequest"+suffix],isNative=true;for(var i=0;i<vendors.length&&!raf;i++){raf=global[vendors[i]+"Request"+suffix];caf=global[vendors[i]+"Cancel"+suffix]||global[vendors[i]+"CancelRequest"+suffix]}if(!raf||!caf){isNative=false;var last=0,id=0,queue=[],frameDuration=1e3/60;raf=function(callback){if(queue.length===0){var _now=now(),next=Math.max(0,frameDuration-(_now-last));last=next+_now;setTimeout(function(){var cp=queue.slice(0);queue.length=0;for(var i=0;i<cp.length;i++){if(!cp[i].cancelled){try{cp[i].callback(last)}catch(e){setTimeout(function(){throw e},0)}}}},Math.round(next))}queue.push({handle:++id,callback:callback,cancelled:false});return id};caf=function(handle){for(var i=0;i<queue.length;i++){if(queue[i].handle===handle){queue[i].cancelled=true}}}}module.exports=function(fn){if(!isNative){return raf.call(global,fn)}return raf.call(global,function(){try{fn.apply(this,arguments)}catch(e){setTimeout(function(){throw e},0)}})};module.exports.cancel=function(){caf.apply(global,arguments)}},{"performance-now":5}],5:[function(require,module,exports){(function(process){(function(){var getNanoSeconds,hrtime,loadTime;if(typeof performance!=="undefined"&&performance!==null&&performance.now){module.exports=function(){return performance.now()}}else if(typeof process!=="undefined"&&process!==null&&process.hrtime){module.exports=function(){return(getNanoSeconds()-loadTime)/1e6};hrtime=process.hrtime;getNanoSeconds=function(){var hr;hr=hrtime();return hr[0]*1e9+hr[1]};loadTime=getNanoSeconds()}else if(Date.now){module.exports=function(){return Date.now()-loadTime};loadTime=Date.now()}else{module.exports=function(){return(new Date).getTime()-loadTime};loadTime=(new Date).getTime()}}).call(this)}).call(this,require("_process"))},{_process:2}],6:[function(require,module,exports){(function(global){module.exports=global.performance&&global.performance.now?function now(){return performance.now()}:Date.now||function now(){return+new Date}}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{}],"raf-loop":[function(require,module,exports){var inherits=require("inherits");var EventEmitter=require("events").EventEmitter;var raf=require("raf");var now=require("right-now");module.exports=Engine;function Engine(fn){if(!(this instanceof Engine))return new Engine(fn);this.running=false;this.last=now();this._frame=0;this._tick=this.tick.bind(this);if(fn)this.on("tick",fn)}inherits(Engine,EventEmitter);Engine.prototype.start=function(){if(this.running)return;this.running=true;this.last=now();this._frame=raf(this._tick);return this};Engine.prototype.stop=function(){this.running=false;if(this._frame!==0)raf.cancel(this._frame);this._frame=0;return this};Engine.prototype.tick=function(){this._frame=raf(this._tick);var time=now();var dt=time-this.last;this.emit("tick",dt);this.last=time}},{events:1,inherits:3,raf:4,"right-now":6}]},{},[]);var rafLoop=require("raf-loop");var COUNT_PARTICLE=100;var MAX_VELOCITY=5;var FRICTION_MAGNITUDE=.07;var els=array(COUNT_PARTICLE,createElement);var positions=create(COUNT_PARTICLE,[window.innerWidth*.5,window.innerHeight*.5,0]);var velocities=create(COUNT_PARTICLE,[rand(-MAX_VELOCITY,MAX_VELOCITY),rand(-MAX_VELOCITY,MAX_VELOCITY),rand(-MAX_VELOCITY,MAX_VELOCITY)]);rafLoop(function(dt){var timeScale=dt/16.6667;var magnitudesVelocity=velocities.map(magnitude);var unitVelocities=velocities.map(normalizeFromMagnitudes(magnitudesVelocity));var magnitudesUnitVelocity=unitVelocities.map(magnitude);var friction=unitVelocities.map(multiplyScalar(-FRICTION_MAGNITUDE));friction=friction.map(function(vector,vectorIdx){var magVelocity=magnitudesVelocity[vectorIdx];var magUnitVelocity=magnitudesUnitVelocity[vectorIdx];if(magVelocity<magUnitVelocity){return vector.map(function(value,valueIDX){return-velocities[vectorIdx][valueIDX]})}else{return vector}});velocities=velocities.map(add(friction));positions=positions.map(add(velocities));els.forEach(updatePosition)}).start();function array(num,from){var rVal=[];var i;if(typeof from==="function"){for(i=0;i<num;i++){rVal.push(from())}}else{for(i=0;i<num;i++){rVal.push(from)}}return rVal}function create(num,from){var rVal=[];var vec;var fromEach=function(from){if(typeof from==="function"){vec.push(from())}else{vec.push(from)}};for(var i=0;i<num;i++){vec=[];rVal.push(vec);from.forEach(fromEach)}return rVal}function rand(min,max){var maxMin=max-min;return function(){return Math.random()*maxMin+min}}function createElement(){var el=document.createElement("div");el.style.width=el.style.height="5px";el.style.background="#BABEEE";el.style.position="absolute";el.style.left=el.style.top=0;document.body.appendChild(el);return el}function updatePosition(el,idx){el.style.transform="perspective(1000px) translate3d("+positions[idx].join("px, ")+"px)"}function add(vectorsToAdd){return function(vector,idxVector){return vector.map(function(value,idxValue){return value+vectorsToAdd[idxVector][idxValue]})}}function multiplyScalar(scalar){return function(vector){return vector.map(function(value){return value*scalar})}}function normalize(vector){var mag=magnitude(vector);return vector.map(function(value){return value/mag})}function normalizeFromMagnitudes(magnitudes){return function(vector,vectorIdx){var mag=magnitudes[vectorIdx];return vector.map(function(value){return value/mag})}}function magnitude(vector){var total=0;vector.forEach(function(value){total+=value*value});return Math.sqrt(total)}
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"raf-loop": "1.0.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment