Skip to content

Instantly share code, notes, and snippets.

@davidguttman
Last active October 1, 2015 16:32
Show Gist options
  • Save davidguttman/94e8118f6393f140a2e4 to your computer and use it in GitHub Desktop.
Save davidguttman/94e8118f6393f140a2e4 to your computer and use it in GitHub Desktop.
requirebin sketch
var bed = require('canvas-testbed')
var Simplex = require('perlin-simplex')
var Coord = require('coordinate-systems')
var simplex = new Simplex()
var TAU = 2 * Math.PI
document.body.style.background = '#eee'
var state = {
curFrame: 0,
rowSpacing: 40,
noiseStepX: 1/200,
noiseStepY: 1/100,
childOffset: 1/150,
fillStyle: 'rgba(20,20,20,0.1)',
maxAge: 10 * 60,
turnRadius: 40,
velocity: 1,
splitAge: 10,
agents: []
}
function render(ctx, width, height) {
state.curFrame += 1
state.height = height
state.width = width
state.nRows = state.height / state.rowSpacing
ctx.fillStyle = state.fillStyle
if (!state.agents.length) {
state.agents.push(new Agent(ctx, state, {
x: width/2,
y: height/2,
heading: Math.PI/4,
velocity: state.velocity,
noiseOffsetX: 1,
noiseOffsetY: 1
}))
}
var nextAgents = []
state.agents.forEach(function (agent) {
agent.update()
})
}
function Agent (ctx, state, opts) {
this.ctx = ctx
this.state = state
this.startFrame = state.curFrame
this.x = opts.x
this.y = opts.y
this.heading = opts.heading
this.velocity = opts.velocity
this.noiseOffsetX = opts.noiseOffsetX
this.noiseOffsetY = opts.noiseOffsetY
this.isAlive = true
return this
}
Agent.prototype.update = function() {
this.age = this.state.curFrame - this.startFrame
if (this.age > this.state.maxAge) {
this.isAlive = false
return
}
this.noiseOffsetX += this.state.noiseStepX
var headingMod = simplex.noise(this.noiseOffsetX, this.noiseOffsetY)
this.heading += headingMod/this.state.turnRadius
var xyDiff = Coord.polar([this.velocity, this.heading]).cart()
this.x += xyDiff[0]
this.y += xyDiff[1]
var x = this.x % this.state.width
var y = this.y % this.state.height
this.ctx.fillRect(x, y, 1, 1)
var shouldSplit = (this.age === this.state.splitAge)
if (shouldSplit) {
this.state.agents.push( new Agent(this.ctx, this.state, {
x: this.x,
y: this.y,
heading: this.heading,
velocity: this.velocity,
noiseOffsetX: this.noiseOffsetX - this.state.childOffset,
noiseOffsetY: this.noiseOffsetY - this.state.childOffset
}) )
}
}
bed(render)
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){var isGL=require("is-webgl-context");var getGL=require("webgl-context");var debounce=require("debounce");var addEvent=require("add-event-listener");function isCanvasContext(obj){var ctx2d=typeof CanvasRenderingContext2D!=="undefined"&&obj instanceof CanvasRenderingContext2D;return obj&&(ctx2d||isGL(obj))}function CanvasApp(render,options){if(!(this instanceof CanvasApp))return new CanvasApp(render,options);if(typeof render==="object"&&render){options=render;render=null}render=typeof render==="function"?render:options.onRender;options=options||{};options.retina=typeof options.retina==="boolean"?options.retina:true;var hasWidth=typeof options.width==="number",hasHeight=typeof options.height==="number";if(hasWidth||hasHeight)options.ignoreResize=true;options.width=hasWidth?options.width:window.innerWidth;options.height=hasHeight?options.height:window.innerHeight;var DPR=options.retina?window.devicePixelRatio||1:1;var canvas,context,attribs=options.contextAttributes||{};this.isWebGL=false;if(isCanvasContext(options.context)){context=options.context;canvas=context.canvas}if(!canvas)canvas=options.canvas||document.createElement("canvas");canvas.width=options.width*DPR;canvas.height=options.height*DPR;if(!context){if(options.context==="webgl"||options.context==="experimental-webgl"){context=getGL({canvas:canvas,attributes:attribs});if(!context){throw"WebGL Context Not Supported -- try enabling it or using a different browser"}}else{context=canvas.getContext(options.context||"2d",attribs)}}this.isWebGL=isGL(context);if(options.retina){canvas.style.width=options.width+"px";canvas.style.height=options.height+"px"}this.running=false;this.width=options.width;this.height=options.height;this.canvas=canvas;this.context=context;this.onResize=options.onResize;this._DPR=DPR;this._retina=options.retina;this._once=options.once;this._ignoreResize=options.ignoreResize;this._lastFrame=null;this._then=Date.now();this.maxDeltaTime=typeof options.maxDeltaTime==="number"?options.maxDeltaTime:1e3/24;this.fps=60;this._frames=0;this._prevTime=this._then;if(!this._ignoreResize){options.resizeDebounce=typeof options.resizeDebounce==="number"?options.resizeDebounce:50;addEvent(window,"resize",debounce(function(){this.resize(window.innerWidth,window.innerHeight)}.bind(this),options.resizeDebounce,false));addEvent(window,"orientationchange",function(){this.resize(window.innerWidth,window.innerHeight)}.bind(this))}if(typeof render==="function"){this.onRender=render.bind(this)}else{this.onRender=function(context,width,height,dt){}}this.renderOnce=function(){var now=Date.now();var dt=Math.min(this.maxDeltaTime,now-this._then);this._frames++;if(now>this._prevTime+1e3){this.fps=Math.round(this._frames*1e3/(now-this._prevTime));this._prevTime=now;this._frames=0}if(!this.isWebGL){this.context.save();this.context.scale(this._DPR,this._DPR)}else{this.context.viewport(0,0,this.width*this._DPR,this.height*this._DPR)}this.onRender(this.context,this.width,this.height,dt);if(!this.isWebGL)this.context.restore();this._then=now};this._renderHandler=function(){if(!this.running)return;if(!this._once){this._lastFrame=requestAnimationFrame(this._renderHandler)}this.renderOnce()}.bind(this);if(typeof options.onReady==="function"){options.onReady.call(this,context,this.width,this.height)}}Object.defineProperty(CanvasApp.prototype,"retinaEnabled",{set:function(v){this._retina=v;this._DPR=this._retina?window.devicePixelRatio||1:1;this.resize(this.width,this.height)},get:function(){return this._retina}});Object.defineProperty(CanvasApp.prototype,"deviceWidth",{get:function(){return this.width*this._DPR}});Object.defineProperty(CanvasApp.prototype,"deviceHeight",{get:function(){return this.height*this._DPR}});CanvasApp.prototype.resetFPS=function(){this._frames=0;this._prevTime=Date.now();this._then=this._prevTime;this.fps=60};CanvasApp.prototype.start=function(){if(this.running)return;if(this._lastFrame)cancelAnimationFrame(this._lastFrame);this.resetFPS();this.running=true;this._lastFrame=requestAnimationFrame(this._renderHandler)};CanvasApp.prototype.stop=function(){if(this._lastFrame){cancelAnimationFrame(this._lastFrame);this._lastFrame=null}this.running=false};CanvasApp.prototype.resize=function(width,height){var canvas=this.canvas;this.width=width;this.height=height;canvas.width=this.width*this._DPR;canvas.height=this.height*this._DPR;if(this._retina){canvas.style.width=this.width+"px";canvas.style.height=this.height+"px"}if(this._once)requestAnimationFrame(this._renderHandler);if(typeof this.onResize==="function")this.onResize(this.width,this.height)};module.exports=CanvasApp},{"add-event-listener":2,debounce:3,"is-webgl-context":5,"webgl-context":6}],2:[function(require,module,exports){addEventListener.removeEventListener=removeEventListener;addEventListener.addEventListener=addEventListener;module.exports=addEventListener;var Events=null;function addEventListener(el,eventName,listener,useCapture){Events=Events||(document.addEventListener?{add:stdAttach,rm:stdDetach}:{add:oldIEAttach,rm:oldIEDetach});return Events.add(el,eventName,listener,useCapture)}function removeEventListener(el,eventName,listener,useCapture){Events=Events||(document.addEventListener?{add:stdAttach,rm:stdDetach}:{add:oldIEAttach,rm:oldIEDetach});return Events.rm(el,eventName,listener,useCapture)}function stdAttach(el,eventName,listener,useCapture){el.addEventListener(eventName,listener,useCapture)}function stdDetach(el,eventName,listener,useCapture){el.removeEventListener(eventName,listener,useCapture)}function oldIEAttach(el,eventName,listener,useCapture){if(useCapture){throw new Error("cannot useCapture in oldIE")}el.attachEvent("on"+eventName,listener)}function oldIEDetach(el,eventName,listener,useCapture){el.detachEvent("on"+eventName,listener)}},{}],3:[function(require,module,exports){var now=require("date-now");module.exports=function debounce(func,wait,immediate){var timeout,args,context,timestamp,result;if(null==wait)wait=100;function later(){var last=now()-timestamp;if(last<wait&&last>0){timeout=setTimeout(later,wait-last)}else{timeout=null;if(!immediate){result=func.apply(context,args);if(!timeout)context=args=null}}}return function debounced(){context=this;args=arguments;timestamp=now();var callNow=immediate&&!timeout;if(!timeout)timeout=setTimeout(later,wait);if(callNow){result=func.apply(context,args);context=args=null}return result}}},{"date-now":4}],4:[function(require,module,exports){module.exports=Date.now||now;function now(){return(new Date).getTime()}},{}],5:[function(require,module,exports){module.exports=function isWebGLContext(ctx){if(!ctx)return false;var gl=ctx;if(typeof ctx.rawgl!=="undefined"){gl=ctx.rawgl}if(typeof WebGLRenderingContext!=="undefined"&&gl instanceof WebGLRenderingContext||typeof WebGL2RenderingContext!=="undefined"&&gl instanceof WebGL2RenderingContext){return true}return false}},{}],6:[function(require,module,exports){module.exports=function(opts){opts=opts||{};var canvas=opts.canvas||document.createElement("canvas");if(typeof opts.width==="number")canvas.width=opts.width;if(typeof opts.height==="number")canvas.height=opts.height;var attribs=opts.attributes||opts.attribs||{};try{gl=canvas.getContext("webgl",attribs)||canvas.getContext("experimental-webgl",attribs)}catch(e){gl=null}return gl}},{}],7:[function(require,module,exports){!function(name,definition){if(typeof module!="undefined")module.exports=definition();else if(typeof define=="function"&&typeof define.amd=="object")define(definition);else this[name]=definition()}("domready",function(){var fns=[],listener,doc=document,hack=doc.documentElement.doScroll,domContentLoaded="DOMContentLoaded",loaded=(hack?/^loaded|^c/:/^loaded|^i|^c/).test(doc.readyState);if(!loaded)doc.addEventListener(domContentLoaded,listener=function(){doc.removeEventListener(domContentLoaded,listener);loaded=1;while(listener=fns.shift())listener()});return function(fn){loaded?setTimeout(fn,0):fns.push(fn)}})},{}],8:[function(require,module,exports){(function(window){var lastTime=0,vendors=["webkit","moz"],requestAnimationFrame=window.requestAnimationFrame,cancelAnimationFrame=window.cancelAnimationFrame,i=vendors.length;while(--i>=0&&!requestAnimationFrame){requestAnimationFrame=window[vendors[i]+"RequestAnimationFrame"];cancelAnimationFrame=window[vendors[i]+"CancelAnimationFrame"]}if(!requestAnimationFrame||!cancelAnimationFrame){requestAnimationFrame=function(callback){var now=+new Date,nextTime=Math.max(lastTime+16,now);return setTimeout(function(){callback(lastTime=nextTime)},nextTime-now)};cancelAnimationFrame=clearTimeout}window.requestAnimationFrame=requestAnimationFrame;window.cancelAnimationFrame=cancelAnimationFrame})(window)},{}],"canvas-testbed":[function(require,module,exports){var domready=require("domready");require("raf.js");var CanvasApp=require("canvas-app");module.exports=function(render,start,options){domready(function(){if(typeof render==="object"&&render){options=render;render=null;start=null}else if(typeof start==="object"&&start){options=start;start=null}options=options||{};if(typeof options.onReady!=="function")options.onReady=start;var runner=CanvasApp(render,options);runner.canvas.setAttribute("id","canvas");document.body.appendChild(runner.canvas);document.body.style.margin="0";document.body.style.overflow="hidden";runner.start()})}},{"canvas-app":1,domready:7,"raf.js":8}]},{},[]);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}({"perlin-simplex":[function(require,module,exports){module.exports=SimplexNoise=function(r){if(r==undefined)r=Math;this.grad3=[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]];this.p=[];for(var i=0;i<256;i++){this.p[i]=Math.floor(r.random()*256)}this.perm=[];for(var i=0;i<512;i++){this.perm[i]=this.p[i&255]}this.simplex=[[0,1,2,3],[0,1,3,2],[0,0,0,0],[0,2,3,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,3,0],[0,2,1,3],[0,0,0,0],[0,3,1,2],[0,3,2,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,3,2,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,0,3],[0,0,0,0],[1,3,0,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,3,0,1],[2,3,1,0],[1,0,2,3],[1,0,3,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,3,1],[0,0,0,0],[2,1,3,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,1,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,0,1,2],[3,0,2,1],[0,0,0,0],[3,1,2,0],[2,1,0,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,1,0,2],[0,0,0,0],[3,2,0,1],[3,2,1,0]]};SimplexNoise.prototype.dot=function(g,x,y){return g[0]*x+g[1]*y};SimplexNoise.prototype.noise=function(xin,yin){var n0,n1,n2;var F2=.5*(Math.sqrt(3)-1);var s=(xin+yin)*F2;var i=Math.floor(xin+s);var j=Math.floor(yin+s);var G2=(3-Math.sqrt(3))/6;var t=(i+j)*G2;var X0=i-t;var Y0=j-t;var x0=xin-X0;var y0=yin-Y0;var i1,j1;if(x0>y0){i1=1;j1=0}else{i1=0;j1=1}var x1=x0-i1+G2;var y1=y0-j1+G2;var x2=x0-1+2*G2;var y2=y0-1+2*G2;var ii=i&255;var jj=j&255;var gi0=this.perm[ii+this.perm[jj]]%12;var gi1=this.perm[ii+i1+this.perm[jj+j1]]%12;var gi2=this.perm[ii+1+this.perm[jj+1]]%12;var t0=.5-x0*x0-y0*y0;if(t0<0)n0=0;else{t0*=t0;n0=t0*t0*this.dot(this.grad3[gi0],x0,y0)}var t1=.5-x1*x1-y1*y1;if(t1<0)n1=0;else{t1*=t1;n1=t1*t1*this.dot(this.grad3[gi1],x1,y1)}var t2=.5-x2*x2-y2*y2;if(t2<0)n2=0;else{t2*=t2;n2=t2*t2*this.dot(this.grad3[gi2],x2,y2)}return 70*(n0+n1+n2)};SimplexNoise.prototype.noise3d=function(xin,yin,zin){var n0,n1,n2,n3;var F3=1/3;var s=(xin+yin+zin)*F3;var i=Math.floor(xin+s);var j=Math.floor(yin+s);var k=Math.floor(zin+s);var G3=1/6;var t=(i+j+k)*G3;var X0=i-t;var Y0=j-t;var Z0=k-t;var x0=xin-X0;var y0=yin-Y0;var z0=zin-Z0;var i1,j1,k1;var i2,j2,k2;if(x0>=y0){if(y0>=z0){i1=1;j1=0;k1=0;i2=1;j2=1;k2=0}else if(x0>=z0){i1=1;j1=0;k1=0;i2=1;j2=0;k2=1}else{i1=0;j1=0;k1=1;i2=1;j2=0;k2=1}}else{if(y0<z0){i1=0;j1=0;k1=1;i2=0;j2=1;k2=1}else if(x0<z0){i1=0;j1=1;k1=0;i2=0;j2=1;k2=1}else{i1=0;j1=1;k1=0;i2=1;j2=1;k2=0}}var x1=x0-i1+G3;var y1=y0-j1+G3;var z1=z0-k1+G3;var x2=x0-i2+2*G3;var y2=y0-j2+2*G3;var z2=z0-k2+2*G3;var x3=x0-1+3*G3;var y3=y0-1+3*G3;var z3=z0-1+3*G3;var ii=i&255;var jj=j&255;var kk=k&255;var gi0=this.perm[ii+this.perm[jj+this.perm[kk]]]%12;var gi1=this.perm[ii+i1+this.perm[jj+j1+this.perm[kk+k1]]]%12;var gi2=this.perm[ii+i2+this.perm[jj+j2+this.perm[kk+k2]]]%12;var gi3=this.perm[ii+1+this.perm[jj+1+this.perm[kk+1]]]%12;var t0=.6-x0*x0-y0*y0-z0*z0;if(t0<0)n0=0;else{t0*=t0;n0=t0*t0*this.dot(this.grad3[gi0],x0,y0,z0)}var t1=.6-x1*x1-y1*y1-z1*z1;if(t1<0)n1=0;else{t1*=t1;n1=t1*t1*this.dot(this.grad3[gi1],x1,y1,z1)}var t2=.6-x2*x2-y2*y2-z2*z2;if(t2<0)n2=0;else{t2*=t2;n2=t2*t2*this.dot(this.grad3[gi2],x2,y2,z2)}var t3=.6-x3*x3-y3*y3-z3*z3;if(t3<0)n3=0;else{t3*=t3;n3=t3*t3*this.dot(this.grad3[gi3],x3,y3,z3)}return 32*(n0+n1+n2+n3)}},{}]},{},[]);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){var isObject=require("amp-is-object");module.exports=function(obj){if(!isObject(obj))return obj;var source,prop;for(var i=1,length=arguments.length;i<length;i++){source=arguments[i];for(prop in source){obj[prop]=source[prop]}}return obj}},{"amp-is-object":4}],2:[function(require,module,exports){var toString=Object.prototype.toString;var nativeIsArray=Array.isArray;module.exports=nativeIsArray||function isArray(obj){return toString.call(obj)==="[object Array]"}},{}],3:[function(require,module,exports){var toString=Object.prototype.toString;module.exports=function isNumber(obj){return toString.call(obj)==="[object Number]"}},{}],4:[function(require,module,exports){module.exports=function isObject(obj){var type=typeof obj;return!!obj&&(type==="function"||type==="object")}},{}],"coordinate-systems":[function(require,module,exports){"use strict";var isArray=require("amp-is-array");var isNumber=require("amp-is-number");var isObject=require("amp-is-object");var extend=require("amp-extend");var degPerRadian=180/Math.PI;var Coordinate=function(config){var isRadian,isDegree,pos={},_x,_y,_z,_r,_t,_p;Object.defineProperty(this,"isRadian",{get:function(x){return isRadian},set:function(x){isRadian=!!x;if(isDegree!==!x){isDegree=!x}}});Object.defineProperty(this,"isDegree",{get:function(x){return isDegree},set:function(x){isDegree=x;if(isRadian!==!x){isRadian=!x}}});Object.defineProperty(pos,"cartesian2d",{get:function(x){return[_x,_y]},set:function(x){_x=x[0];_y=x[1]}});Object.defineProperty(pos,"cartesian3d",{get:function(x){return[_x,_y,_z]},set:function(x){_x=x[0];_y=x[1];_z=x[2]}});Object.defineProperty(pos,"polar",{get:function(x){return[_r,_t]},set:function(x){_r=x[0];_t=x[1]}});Object.defineProperty(pos,"cylindrical",{get:function(x){return[_r,_t,_z]},set:function(x){_r=x[0];_t=x[1];_z=x[2]}});Object.defineProperty(pos,"spherical",{get:function(x){return[_r,_t,_p]},set:function(x){_r=x[0];_t=x[1];_p=x[2]}});if(config.isDegree&&!config.isRadian){this.isDegree=true}else{this.isRadian=true}if(!config.label||!config.coords){throw new Error("no coordinate type defined")}this.initialType=config.label;this.pos=pos;this.pos[config.label]=config.coords};Coordinate.prototype.cartesian=function(){return this.cart.apply(this,arguments)};Coordinate.prototype.cart=function(options){var temp;options=options||{};switch(this.initialType){case"cartesian2d":return this.pos.cartesian2d;case"cartesian3d":return this.pos.cartesian3d;case"polar":this.pos.cartesian2d=Coordinate.polarToCart2d(this.pos.polar,this.isDegree);return this.pos.cartesian2d;case"cylindrical":temp=Coordinate.polarToCart2d(this.pos.polar,this.isDegree);this.pos.cartesian3d=[temp[0],temp[1],this.pos.cylindrical[2]];return this.pos.cartesian3d;case"spherical":this.pos.cartesian3d=Coordinate.sphericalToCart3d(this.pos.spherical,this.isDegree);return this.pos.cartesian3d;default:throw new Error("cannot convert to/from original/requested types")}};Coordinate.prototype.cylindrical=function(){return this.cyl.apply(this,arguments)};Coordinate.prototype.cyl=function(options){var temp;options=options||{};switch(this.initialType){case"cartesian2d":temp=Coordinate.cartesian2dToPolar(this.pos.cartesian2d,this.isDegree,options.center);this.pos.cylindrical=[temp[0],temp[1],0];return this.pos.cylindrical;case"cartesian3d":this.pos.cylindrical=Coordinate.cartesian3dToCylindrical(this.pos.cartesian3d,this.isDegree,options.center);return this.pos.cylindrical;case"polar":temp=this.pos.polar;return[temp[0],temp[1],0];case"cylindrical":return this.pos.cylindrical;case"spherical":this.pos.cylindrical=Coordinate.sphericalToCylindrical(this.pos.spherical,this.isDegree);return this.pos.cylindrical;default:throw new Error("cannot convert to/from original/requested types")}};Coordinate.prototype.pol=function(){return this.polar.apply(this,arguments)};Coordinate.prototype.polar=function(options){options=options||{};switch(this.initialType){case"cartesian2d":this.pos.polar=Coordinate.cartesian2dToPolar(this.pos.cartesian2d,this.isDegree,options.center);return this.pos.polar;case"polar":return this.pos.polar;default:throw new Error("cannot convert to/from original/requested types")}};Coordinate.prototype.spherical=function(){return this.sph.apply(this,arguments)};Coordinate.prototype.sph=function(options){var temp;options=options||{};switch(this.initialType){case"cartesian2d":temp=Coordinate.cartesian2dToPolar(this.pos.cartesian2d,this.isDegree,options.center);this.pos.spherical=[temp[0],temp[1],0];return this.pos.spherical;case"cartesian3d":this.pos.spherical=Coordinate.cartesian3dToSpherical(this.pos.cartesian3d,this.isDegree,options.center);return this.pos.spherical;case"polar":temp=this.pos.polar;return[temp[0],temp[1],0];case"cylindrical":this.pos.spherical=Coordinate.cylindricalToSpherical(this.pos.cylindrical,this.isDegree);return this.pos.spherical;case"spherical":return this.pos.spherical;default:throw new Error("cannot convert to/from original/requested types")}};Coordinate.cartesian=function(x){return Coordinate.cart(x)};Coordinate.cart=function(options){var baseCoord;if(isArray(options)){options={coords:options}}if(isObject(options)&&isArray(options.coords)){Coordinate.arrToNumeric(options.coords);if(options.coords.length<2||options.coords.length>3){throw new Error("expected exactly 2 or exactly 3 cartesian options")}baseCoord={label:"cartesian2d",options:options.coords};baseCoord=extend(baseCoord,options);if(options.coords.length===2){return new Coordinate(baseCoord)}baseCoord.label="cartesian3d";return new Coordinate(baseCoord)}throw new Error("expected options w/ array of [x,y,(z?)] coords")};Coordinate.cylindrical=function(x){return Coordinate.cyl(x)};Coordinate.cyl=function(options){var baseCoord;if(isArray(options)){options={coords:options}}if(isObject(options)&&isArray(options.coords)){Coordinate.arrToNumeric(options.coords);if(options.coords.length!==3){throw new Error("expected exactly 3 params [r, t, z]")}baseCoord={label:"cylindrical",coords:options.coords};baseCoord=extend(baseCoord,options);return new Coordinate(baseCoord)}throw new Error("expected options w/ array of [r, t, z] coords")};Coordinate.polar=function(x){return Coordinate.pol(x)};Coordinate.pol=function(options){var baseCoord;if(isArray(options)){options={coords:options}}if(isObject(options)&&isArray(options.coords)){Coordinate.arrToNumeric(options.coords);if(options.coords.length!==2){throw new Error("expected exactly 2 params [r, t]")}baseCoord={label:"polar",coords:options.coords};baseCoord=extend(baseCoord,options);return new Coordinate(baseCoord)}throw new Error("expected array of [r, t] options")};Coordinate.spherical=function(options){return Coordinate.sph(options)};Coordinate.sph=function(options){var baseCoord;if(isArray(options)){options={coords:options}}if(isObject(options)&&isArray(options.coords)){Coordinate.arrToNumeric(options.coords);if(options.coords.length!==3){throw new Error("expected exactly 3 params [r, t, p]")}baseCoord={label:"spherical",coords:options.coords};baseCoord=extend(baseCoord,options);return new Coordinate(baseCoord)}throw new Error("expected options w/ array of [r, t, p] coords")};Coordinate.arrToNumeric=function(nums){var num;if(!isArray(nums)){throw new TypeError("expected array of number-like values")}for(var i=nums.length-1;i>=0;i--){num=nums[i];if(typeof num==="string"){num=parseFloat(num)}if(!isNumber(num)){throw new TypeError(num+" not numeric or numeric-like")}}};Coordinate.polarToCart2d=function(rt,isDegree){var r,t,x,y;r=rt[0];t=rt[1];if(isDegree){t=t*(1/degPerRadian)}x=r*Math.cos(t);y=r*Math.sin(t);return[x,y]};Coordinate.cartesian2dToPolar=function(xy,isDegree,center){var x,y,r,t;if(!isArray(xy)&&xy.length!==2){throw new TypeError("expected [x, y] xy array")}x=xy[0];y=xy[1];if(center&&!isArray(center)&&center.length!==2){throw new TypeError("expected [x, y] center array")}if(center){x=x-center[0];y=y-center[1]}r=Math.sqrt(x*x+y*y);t=Math.atan2(y,x);if(isDegree){t=t*degPerRadian}return[r,t]};Coordinate.cartesian3dToCylindrical=function(xyz,isDegree,center){var x=xyz[0],y=xyz[1],z=xyz[2],rt;rt=Coordinate.cartesian2dToPolar([x,y],isDegree,center);return[rt[0],rt[1],z]};Coordinate.cartesian3dToSpherical=function(xyz,isDegree,center){if(center&&center.length!==3){throw new Error("expected center value to have [x, y, z] coords"+"for locating sphere center")}var x=xyz[0],y=xyz[1],z=xyz[2],x2,y2,z2,r,t,p;if(center){x=x-center[0];y=y-center[1];z=z-center[2]}x2=x*x;y2=y*y;z2=z*z;r=Math.sqrt(x2+y2+z2);if(!r){p=t=0}else{t=Math.atan2(y,x);p=Math.atan2(Math.sqrt(x2+y2),z);if(isDegree){t=t*degPerRadian;p=p*degPerRadian}}return[r,t,p]};Coordinate.cylindricalToSpherical=function(rtz,isDegree){var r=rtz[0],t=rtz[1],z=rtz[2];var sr,sp;if(isDegree){t=t/degPerRadian}sr=Math.sqrt(r*r+z*z);sp=Math.atan2(r,z);if(isDegree){sp=sp*degPerRadian;t=t*degPerRadian}return[sr,t,sp]};Coordinate.sphericalToCart3d=function(rtp,isDegree){var r=rtp[0],t=rtp[1],p=rtp[2],x,y,z;if(isDegree){t=t/degPerRadian;p=p/degPerRadian}x=r*Math.sin(p)*Math.cos(t);y=r*Math.sin(p)*Math.sin(t);z=r*Math.cos(p);return[x,y,z]};Coordinate.sphericalToCylindrical=function(rtp,isDegree){var r=rtp[0],t=rtp[1],p=rtp[2],cr,z;if(isDegree){t=t/degPerRadian;p=p/degPerRadian}cr=r*Math.sin(p);z=r*Math.cos(p);if(isDegree){t=t*degPerRadian;p=p*degPerRadian}return[cr,t,z]};module.exports=Coordinate},{"amp-extend":1,"amp-is-array":2,"amp-is-number":3,"amp-is-object":4}]},{},[]);var bed=require("canvas-testbed");var Simplex=require("perlin-simplex");var Coord=require("coordinate-systems");var simplex=new Simplex;var TAU=2*Math.PI;document.body.style.background="#eee";var state={curFrame:0,rowSpacing:40,noiseStepX:1/200,noiseStepY:1/100,childOffset:1/150,fillStyle:"rgba(20,20,20,0.1)",maxAge:10*60,turnRadius:40,velocity:1,splitAge:10,agents:[]};function render(ctx,width,height){state.curFrame+=1;state.height=height;state.width=width;state.nRows=state.height/state.rowSpacing;ctx.fillStyle=state.fillStyle;if(!state.agents.length){state.agents.push(new Agent(ctx,state,{x:width/2,y:height/2,heading:Math.PI/4,velocity:state.velocity,noiseOffsetX:1,noiseOffsetY:1}))}var nextAgents=[];state.agents.forEach(function(agent){agent.update()})}function Agent(ctx,state,opts){this.ctx=ctx;this.state=state;this.startFrame=state.curFrame;this.x=opts.x;this.y=opts.y;this.heading=opts.heading;this.velocity=opts.velocity;this.noiseOffsetX=opts.noiseOffsetX;this.noiseOffsetY=opts.noiseOffsetY;this.isAlive=true;return this}Agent.prototype.update=function(){this.age=this.state.curFrame-this.startFrame;if(this.age>this.state.maxAge){this.isAlive=false;return}this.noiseOffsetX+=this.state.noiseStepX;var headingMod=simplex.noise(this.noiseOffsetX,this.noiseOffsetY);this.heading+=headingMod/this.state.turnRadius;var xyDiff=Coord.polar([this.velocity,this.heading]).cart();this.x+=xyDiff[0];this.y+=xyDiff[1];var x=this.x%this.state.width;var y=this.y%this.state.height;this.ctx.fillRect(x,y,1,1);var shouldSplit=this.age===this.state.splitAge;if(shouldSplit){this.state.agents.push(new Agent(this.ctx,this.state,{x:this.x,y:this.y,heading:this.heading,velocity:this.velocity,noiseOffsetX:this.noiseOffsetX-this.state.childOffset,noiseOffsetY:this.noiseOffsetY-this.state.childOffset}))}};bed(render);
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"canvas-testbed": "1.0.4",
"perlin-simplex": "0.0.2",
"coordinate-systems": "1.1.0"
}
}
<!-- contents of this file will be placed inside the <body> -->
<!-- contents of this file will be placed inside the <head> -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment