2014-03-10 03:57:59 +00:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
2014-08-17 03:23:48 +00:00
< title > terra.js< / title >
< link rel = "stylesheet" href = "main.css" >
< link href = 'http://fonts.googleapis.com/css?family=Open+Sans:400,700' rel = 'stylesheet' type = 'text/css' >
2014-03-10 03:57:59 +00:00
< / head >
< body >
2014-08-17 03:23:48 +00:00
< div class = "fullPage splash" >
< div class = "vcent" > < / div >
< header id = "header" >
< h1 > terra.js < span > alpha< / span > < / h1 >
< p > A JavaScript framework for simple biological simulations and cellular automata.< / p >
2014-08-21 08:07:30 +00:00
< a data-scroll href = "#main" id = "scroller1" class = "downArrow" > ⬇< / a >
2014-08-17 03:23:48 +00:00
< / header >
< / div >
< nav >
< ul >
< li > < a data-scroll href = "#usage" > Usage< / a > < / li >
< li > < a data-scroll href = "#examples" > Examples< / a > < / li >
2014-08-22 23:27:50 +00:00
< li > < a data-scroll href = "#creatures" > Creatures< / a > < / li >
< li > < a data-scroll href = "#terrarium" > Terrarium< / a > < / li >
2014-08-17 03:23:48 +00:00
< li > < a href = "https://github.com/rileyjshaw/terra" > GitHub< / a > < / li >
< / ul >
< / nav >
< div id = "main" class = "main" >
< p > terra is a < strong > super customizable< / strong > framework for creating and analyzing biological simulations. It's open-source and licenced under MIT.< / p >
2014-08-17 06:23:48 +00:00
2014-08-17 03:23:48 +00:00
< h2 id = "usage" > Usage< / h2 >
2014-08-17 06:23:48 +00:00
< h3 > Including terra< / h3 >
< p > Getting started is as easy as including the script!< / p >
< pre > < code class = "language-markup" > < script src="path/to/terra.min.js"> < /script> < / code > < / pre >
2014-08-24 06:40:44 +00:00
< p > terra can also be used as a module with most popular module systems: < a class = "question" target = "_blank" href = "https://github.com/umdjs/umd" > ?< / a > < / p >
< pre > < code class = "language-javascript" > // CommonJS
var terra = require('./terra.min.js');
// ...
// AMD
define(['./terra.min.js'] , function (terra) {
2014-08-25 17:29:42 +00:00
return function () { //... };
2014-08-24 06:40:44 +00:00
});
// ...and if you're not using a module system, it'll be in
window.terra;< / code > < / pre >
< p > If you manage dependencies with < a href = "http://bower.io/" > Bower< / a > , you're in luck!< / p >
< pre > < code class = "language-bash" > bower install terra< / code > < / pre >
2014-08-17 06:23:48 +00:00
< h3 > Creating creatures< / h3 >
2014-08-21 08:07:30 +00:00
< p > Let's create a simple creature using the creatureFactory. Each creature requires a type.< / p >
2014-08-17 06:23:48 +00:00
< pre > < code class = "language-javascript" > terra.creatureFactory.register({
type: 'firstCreature'
});< / code > < / pre >
2014-08-22 23:27:50 +00:00
< p > This creature is valid, but it's pretty boring. To make a more interesting creature, let's override some of the default < a data-scroll href = "#creatures" > attributes and methods< / a > .< / p >
2014-08-17 06:23:48 +00:00
< pre > < code class = "language-javascript" > terra.creatureFactory.register({
2014-08-17 03:23:48 +00:00
type: 'secondCreature',
2014-08-21 08:07:30 +00:00
color: [120, 0, 240],
sustainability: 6,
reproduceLv: 1
2014-08-17 06:23:48 +00:00
});< / code > < / pre >
2014-08-21 08:07:30 +00:00
< p > We've just created a purple creature that only eats if 6 or more plants are around it. These creatures basically seek out an edge or corner and die there.< / p >
2014-08-17 06:23:48 +00:00
2014-08-21 08:07:30 +00:00
< h3 > Creating the environment< / h3 >
< p > To run a simulation, we'll need to create an environment. Let's make a 25x25 grid, populate 10% of the space with our lonely purple creature, and fill the rest with simple plants.< / p >
< pre > < code class = "language-javascript" > var ex1 = new terra.Terrarium(25, 25, 'ex1');
2014-08-22 23:27:50 +00:00
ex1.populate([['secondCreature', 10], ['simplePlant', 90]]);< / code > < / pre >
2014-08-17 06:23:48 +00:00
2014-08-21 08:07:30 +00:00
< h3 > Running a simulation< / h3 >
2014-08-17 06:23:48 +00:00
2014-08-21 08:07:30 +00:00
< p > Terrariums have a few methods that allow you to interact with the simulation. Let's animate it and see how it does for the first 300 steps.< / p >
< pre id = "ex1End" > < code class = "language-javascript" > ex1.animate(300);< / code > < / pre >
2014-08-17 03:23:48 +00:00
2014-08-22 23:27:50 +00:00
< p > That's all there is to it! Though it's possible to generate complex behaviours by simply overriding default values, the real fun comes when you realize that < a data-scroll href = "#customOptions" > creatures are entirely customizable< / a > .< / p >
2014-08-17 03:23:48 +00:00
< h2 id = "examples" > Examples< / h2 >
2014-08-17 06:23:48 +00:00
2014-08-17 03:23:48 +00:00
< h3 id = "gol" > Conway's Game of Life < a class = "question" target = "_blank" href = "http://en.wikipedia.org/wiki/Conway's_Game_of_Life" > ?< / a > < / h3 >
2014-08-23 23:17:15 +00:00
< pre > < code class = "language-javascript" > var gameOfLife = new terra.Terrarium(25, 25);
2014-08-23 23:16:26 +00:00
terra.creatureFactory.register({
2014-08-17 06:23:48 +00:00
type: 'GoL',
colorFn: function () { return this.alive ? this.color + ',1' : '0,0,0,0'; },
wait: function () {},
isDead: function () { return false; },
queue: function (neighbors) {
var surrounding = _.filter(neighbors, function (spot) {
return spot.creature.alive;
}).length;
2014-08-21 08:07:30 +00:00
this.alive = surrounding === 3 || surrounding === 2 & & this.alive;
2014-08-17 06:23:48 +00:00
return false;
}
}, function () {
2014-08-21 08:07:30 +00:00
this.alive = Math.random() < 0.5;
2014-08-23 23:16:26 +00:00
});
gameOfLife.populate([['GoL', 100]]);
gameOfLife.animate();< / code > < / pre >
2014-08-17 03:23:48 +00:00
2014-08-21 08:07:30 +00:00
< h3 id = "cyclic" > Cyclic Cellular Automaton < a class = "question" target = "_blank" href = "http://en.wikipedia.org/wiki/Cyclic_cellular_automaton" > ?< / a > < / h3 >
2014-08-24 00:04:02 +00:00
< pre > < code class = "language-javascript" > var cyclic = new terra.Terrarium(100, 100);
2014-08-23 23:16:26 +00:00
terra.creatureFactory.register({
2014-08-17 06:23:48 +00:00
type: 'cyclic',
2014-08-21 08:07:30 +00:00
colors: ['255,0,0,1', '255,96,0,1', '255,191,0,1', '223,255,0,1', '128,255,0,1', '32,255,0,1', '0,255,64,1', '0,255,159,1', '0,255,255,1', '0,159,255,1', '0,64,255,1', '32,0,255,1', '127,0,255,1', '223,0,255,1', '255,0,191,1', '255,0,96,1'],
2014-08-17 06:23:48 +00:00
colorFn: function () { return this.colors[this.state];},
wait: function () {},
isDead: function () { return false; },
queue: function (neighbors) {
2014-08-21 08:07:30 +00:00
var next = (this.state + 1) % 16;
2014-08-17 06:23:48 +00:00
var changing = _.some(neighbors, function (spot) {
return spot.creature.state === next;
});
if (changing) this.state = next;
}
}, function () {
2014-08-21 08:07:30 +00:00
this.state = Math.floor(Math.random() * 16);
2014-08-23 23:16:26 +00:00
});
cyclic.populate([['cyclic', 100]]);
cyclic.animate();< / code > < / pre >
2014-08-17 03:23:48 +00:00
2014-08-24 01:36:48 +00:00
< h3 id = "brutesAndBullies" > Brutes and Bullies< / h3 >
2014-08-24 00:04:02 +00:00
< pre > < code class = "language-javascript" > // the demo running at the top of this page
var paTerrarium = new terra.Terrarium(25, 25);
terra.creatureFactory.register({
type: 'plant',
color: [0, 120, 0],
size: 10,
initialEnergy: 5,
maxEnergy: 20,
wait: function() {
// photosynthesis :)
this.energy += 1;
},
move: false,
reproduceLv: 0.65
});
2014-08-24 01:25:47 +00:00
creatureFactory.register({
2014-08-24 01:36:48 +00:00
type: 'brute',
2014-08-24 00:04:02 +00:00
color: [0, 255, 255],
maxEnergy: 50,
2014-08-24 01:25:47 +00:00
initialEnergy: 10,
size: 20
2014-08-24 00:04:02 +00:00
});
2014-08-24 01:25:47 +00:00
creatureFactory.register({
2014-08-24 00:04:02 +00:00
type: 'bully',
color: [241, 196, 15],
2014-08-24 01:36:48 +00:00
initialEnergy: 20,
2014-08-24 01:25:47 +00:00
reproduceLv: 0.6,
2014-08-24 00:04:02 +00:00
sustainability: 3
});
2014-08-24 01:36:48 +00:00
paTerrarium.populate([['plant', 50], ['brute', 5], ['bully', 5]]);
2014-08-24 00:04:02 +00:00
paTerrarium.animate();< / code > < / pre >
2014-08-22 23:27:50 +00:00
< p > If you come up with a cool example, < a href = "mailto:i@rileyjshaw.com" > let me know< / a > ! I'll add it to this list and credit you.< / p >
2014-08-17 03:23:48 +00:00
2014-08-22 23:27:50 +00:00
< h2 id = "creatures" > Creatures< / h2 >
< p > Creatures are registered with < pre > < code class = "language-javascript" > terra.creatureFactory.register(options, init)< / code > < / pre > < / p >
< p > The following methods and attributes can be passed in an object as the first argument:< / p >
< h3 id = "creatureOptions" > Required< / h3 >
2014-08-21 08:07:30 +00:00
< ul class = "defaults" >
< li >
< h4 > < span class = "token keyword" > string< / span > type< / h4 >
2014-08-23 23:43:40 +00:00
< p > Creature type, to be used later in < a data-scroll href = "#terrariumMethods" class = "token function" > populate( )< / a > .< / p >
2014-08-21 08:07:30 +00:00
< / li >
2014-08-17 03:23:48 +00:00
< / ul >
< h3 > Optional< / h3 >
2014-08-21 08:07:30 +00:00
< ul class = "defaults" >
2014-08-22 23:27:50 +00:00
< li id = "actionRadius" >
< h4 > < span class = "token keyword" > int< / span > actionRadius< / h4 >
< p > A creature's vision and movement range for each step.< / p >
< ul >
< li > Default: 1< / li >
< / ul >
< / li >
< li >
< h4 > < span class = "token keyword" > char< / span > character< / h4 >
< p > ASCII character used to visually represent a creature.< / p >
< ul >
< li > Default: undefined (fills cell)< / li >
< / ul >
< / li >
2014-08-21 08:07:30 +00:00
< li >
< h4 > < span class = "token keyword" > int [3]< / span > color< / h4 >
< p > RGB components of a creature's display color.< / p >
< ul >
< li > Range: [0, 255]< / li >
< li > Default: random< / li >
< / ul >
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > function< / span > colorFn< / h4 >
< p > How a creature's color is determined at each step.< / p >
< ul >
< li > Returns: < span class = "mono" > < span class = "token keyword" > string< / span > < / span > of comma-separated RGBA components.< / li >
< / ul >
< / li >
< li >
< h4 > < span class = "token keyword" > int< / span > efficiency< / h4 >
< p > Conversion ratio of food to energy. Food energy × efficiency = gained energy.< / p >
< ul >
< li > Default: 0.7< / li >
< / ul >
< / li >
< li id = "initialEnergy" >
2014-08-21 08:07:30 +00:00
< h4 > < span class = "token keyword" > float< / span > initialEnergy< / h4 >
< p > Energy level that a creature has at the start of its life.
< ul >
2014-08-22 23:27:50 +00:00
< li > Range: (0, < a data-scroll href = "#maxEnergy" > maxEnergy< / a > ]< / li >
2014-08-21 08:07:30 +00:00
< li > Default: 50< / li >
< / ul >
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > function< / span > isDead< / h4 >
< p > Determines whether a creature should be removed at the beginning of a step.< / p >
< ul >
< li > Returns: < span class = "mono" > < span class = "token keyword" > boolean< / span > < / span > < / li >
< / ul >
< / li >
< li id = "maxEnergy" >
2014-08-21 08:07:30 +00:00
< h4 > < span class = "token keyword" > float< / span > maxEnergy< / h4 >
< p > Maximum energy that a creature can have; excess energy is discarded.< / p >
< ul >
< li > Default: 100< / li >
< li > Minimum: 0< / li >
< / ul >
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > function< / span > move< / h4 >
< p > How a creature moves.< / p >
< ul >
< li > Parameters: < span class = "mono" > < span class = "token keyword" > {coords, creature} []< / span > neighbors< / span > < / li >
< li > Default: Look for edible creatures; if none are found, look for open spaces to move to; if none are found, wait.< / li >
< li > Returns: < span class = "mono" > {x, y, creature, successFn} || false< / span > < / li >
< / ul >
2014-08-21 08:07:30 +00:00
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > float< / span > moveLv< / h4 >
2014-08-21 08:07:30 +00:00
< p > < / p >
2014-08-22 23:27:50 +00:00
< ul >
< p > Percentage of a creature's max energy below which it will stop moving (used in the default < a data-scroll href = "#queue" > queue< / a > method).< / p >
2014-08-24 01:25:47 +00:00
< li > Default: 0< / li >
2014-08-22 23:27:50 +00:00
< li > Range: [0, 1]< / li >
< / ul >
< / li >
< li id = "queue" >
< h4 > < span class = "token keyword" > function< / span > queue< / h4 >
< p > Main entry point for behavior; called for each creature on each iteration.< / p >
< ul >
< li > Parameters: < span class = "mono" > < span class = "token keyword" > {coords, creature} []< / span > neighbors< / span > < / li >
< li > Default: Reproduce if energy is sufficient, otherwise move if energy is sufficient, otherwise wait.< / li >
< li > Returns: < span class = "mono" > {x, y, creature} || false< / span > < / li >
< / ul >
2014-08-21 08:07:30 +00:00
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > function< / span > reproduce< / h4 >
< p > How a creature reproduces.< / p >
2014-08-21 08:07:30 +00:00
< ul >
2014-08-22 23:27:50 +00:00
< li > Parameters: < span class = "mono" > < span class = "token keyword" > {coords, creature} []< / span > neighbors< / span > < / li >
< li > Default: Look for neighboring open space; if any exists, randomly place a new creature and lose energy equal to the child's < a data-scroll href = "#initialEnergy" > initialEnergy< / a > .< / li >
< li > Returns: < span class = "mono" > {x, y, creature, successFn, failureFn} || false< / span > < / li >
2014-08-21 08:07:30 +00:00
< / ul >
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > float< / span > reproduceLv< / h4 >
< p > Percentage of a creature's max energy above which it will reproduce (used in the default < a data-scroll href = "#queue" > queue< / a > method).< / p >
< ul >
< li > Default: 0.7< / li >
< li > Range: [0, 1]< / li >
< / ul >
2014-08-21 08:07:30 +00:00
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > int< / span > size< / h4 >
< p > A creature's size; by default, creatures can only eat creatures smaller than them.< / p >
< ul >
< li > Default: 50< / li >
< / ul >
2014-08-21 08:07:30 +00:00
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > int< / span > sustainability< / h4 >
< p > Number of visible food sources needed before a creature will eat.< / p >
< ul >
< li > Default: 2< / li >
< li > Range: (0, 16 × < a data-scroll href = "#actionRadius" > actionRadius< / a > - 8]< / li >
< / ul >
2014-08-21 08:07:30 +00:00
< / li >
< li >
2014-08-22 23:27:50 +00:00
< h4 > < span class = "token keyword" > function< / span > wait< / h4 >
< p > What happens when a creature waits.< / p >
< ul >
< li > Default: Creature loses 5 energy.< / li >
< / ul >
< / li >
< li id = "customOptions" >
< h4 > < span class = "token keyword" > *< / span > *< / h4 >
< p > The best part about creatures is that you can add < em > whatever you want< / em > to them! In addition to overriding any of the above properties, creatures will accept any methods and properties you throw at 'em.< / p >
2014-08-21 08:07:30 +00:00
< / li >
2014-08-17 03:23:48 +00:00
< / ul >
2014-08-22 23:27:50 +00:00
< p > The second argument to terra.creatureFactory.register is the init function. This function is run within a creature's constructor and allows you to set different attributes for individual creatures. For example, in the < a data-scroll href = "#cyclic" > Cyclic Cellular Automaton< / a > example above we see the following init function:< / p >
< pre > < code class = "language-javascript" > function () {
this.state = Math.floor(Math.random() * 16);
});< / code > < / pre >
< p > Whenever a new creature is created of type 'cyclic', it will be randomly assigned a state of 0 to 15.< / p >
< h2 id = "terrarium" > Terrarium< / h2 >
< p > Terrariums are where the action happens. They're initialized with the following constructor:< / p >
2014-08-23 23:17:15 +00:00
< pre > < code class = "language-javascript" > var t = new terra.Terrarium(width, height, id, cellSize, insertAfter);< / code > < / pre >
2014-08-22 23:27:50 +00:00
< h3 > Required< / h3 >
2014-08-21 08:07:30 +00:00
< ul class = "defaults" >
2014-08-22 23:27:50 +00:00
< li >
< h4 > < span class = "token keyword" > int< / span > width< / h4 >
< p > Number of cells in the x-direction.< / p >
< / li >
< li >
< h4 > < span class = "token keyword" > int< / span > height< / h4 >
< p > Number of cells in the y-direction.< / p >
< / li >
2014-08-17 03:23:48 +00:00
< / ul >
2014-08-22 23:27:50 +00:00
< h3 > Optional< / h3 >
< ul class = "defaults" >
< li >
< h4 > < span class = "token keyword" > string< / span > id< / h4 >
< p > id assigned to the generated canvas.< / p >
< / li >
< li >
< h4 > < span class = "token keyword" > int< / span > cellSize< / h4 >
< p > Pixel width of each cell.< / p >
< ul >
< li > Default: 10< / li >
< / ul >
< / li >
< li >
< h4 > < span class = "token keyword" > string< / span > insertAfter< / h4 >
< p > id of the element to insert the canvas after.< / p >
< ul >
< li > Default: canvas is appended to < code class = "language-markup" > document.body< / code > < / li >
< / ul >
< / li >
< / ul >
2014-08-23 23:43:40 +00:00
< p id = "terrariumMethods" > Once initialized, terrariums have a few exposed methods. Using our terrarium < code class = "language-javascript" > t< / code > that we just created:< / p >
2014-08-22 23:27:50 +00:00
< pre > < code class = "language-javascript" > t.populate(creatures);
//populates the terrarium with a set distribution of creatures.
//< creatures> is an array of arrays of the form [string 'creatureName', int fillPercent]
t.grid = t.step(steps);
//t.step returns the next step of the simulation, or the grid after < steps> steps if specified.
//here, we're setting the terrarium's grid to the returned grid.
t.draw();
//updates the canvas to reflect the current grid
t.animate(steps, fn);
//starts animating the simulation. The simulation will stop after < steps> steps
//if specified, and call < fn> as a callback once the animation finishes.
t.stop();
//stops a currently running animation< / code > < / pre >
2014-08-17 03:23:48 +00:00
2014-08-22 23:27:50 +00:00
< p > Still want more? Check out the source on < a href = "https://github.com/rileyjshaw/terra" > GitHub< / a > !< / p >
2014-08-17 03:23:48 +00:00
< / div >
< footer > Created with ❤ by < a href = "http://rileyjshaw.com" > rileyjshaw< / a > . Inspired by < a href = "http://eloquentjavascript.net/" > Marijn Haverbeke< / a > and < a href = "https://www.wolframscience.com/" > Stephen Wolfram< / a > .< / footer >
< script src = "terra.demo.min.js" > < / script >
2014-03-10 03:57:59 +00:00
< / body >
< / html >