-
-
-
- Service discovery and configuration made easy.
- Distributed, highly available, and
- datacenter-aware.
-
+
diff --git a/website/source/javascripts/app/Circle.js b/website/source/javascripts/app/Circle.js
new file mode 100644
index 000000000..bd61b9c1a
--- /dev/null
+++ b/website/source/javascripts/app/Circle.js
@@ -0,0 +1,627 @@
+// jshint unused:false
+var Circle = {
+ "Points": [
+ {
+ "id": "point-0",
+ "x": 329.40000000000003,
+ "y": 282.96000000000004
+ },
+ {
+ "id": "point-1",
+ "x": 355.26,
+ "y": 224.82
+ },
+ {
+ "id": "point-2",
+ "x": 282.66,
+ "y": 330.3
+ },
+ {
+ "id": "point-5",
+ "x": 279.12,
+ "y": 224.10000000000002
+ },
+ {
+ "id": "point-8",
+ "x": 217.26000000000002,
+ "y": 246.06
+ },
+ {
+ "id": "point-11",
+ "x": 190.01999999999998,
+ "y": 293.52
+ },
+ {
+ "id": "point-14",
+ "x": 209.21999999999997,
+ "y": 360.9
+ },
+ {
+ "id": "point-17",
+ "x": 127.08000000000001,
+ "y": 257.88
+ },
+ {
+ "id": "point-20",
+ "x": 124.55999999999999,
+ "y": 354.12
+ },
+ {
+ "id": "point-26",
+ "x": 48.6,
+ "y": 303.06
+ },
+ {
+ "id": "point-28",
+ "x": 353.1,
+ "y": 128.46
+ },
+ {
+ "id": "point-32",
+ "x": 237.48000000000002,
+ "y": 188.51999999999998
+ },
+ {
+ "id": "point-38",
+ "x": 172.68,
+ "y": 183
+ },
+ {
+ "id": "point-41",
+ "x": 130.68,
+ "y": 189
+ },
+ {
+ "id": "point-47",
+ "x": 61.2,
+ "y": 198.96000000000004
+ },
+ {
+ "id": "point-53",
+ "x": 8.34,
+ "y": 240.48000000000002
+ },
+ {
+ "id": "point-55",
+ "x": 236.88000000000002,
+ "y": 107.28000000000002
+ },
+ {
+ "id": "point-59",
+ "x": 165.23999999999998,
+ "y": 97.8
+ },
+ {
+ "id": "point-65",
+ "x": 79.91999999999999,
+ "y": 121.14000000000001
+ },
+ {
+ "id": "point-74",
+ "x": 0,
+ "y": 160.44
+ },
+ {
+ "id": "point-78",
+ "x": 305.7,
+ "y": 50.88
+ },
+ {
+ "id": "point-79",
+ "x": 251.82,
+ "y": 14.879999999999999
+ },
+ {
+ "id": "point-83",
+ "x": 197.88,
+ "y": -0.12000000000000001
+ },
+ {
+ "id": "point-89",
+ "x": 132.6,
+ "y": 6.06
+ },
+ {
+ "id": "point-95",
+ "x": 44.64000000000001,
+ "y": 60.96
+ },
+ {
+ "id": "point-98",
+ "x": 18.060000000000002,
+ "y": 99.60000000000001
+ }
+ ],
+ "Polygons": [
+ {
+ "id": "poly-0",
+ "color": {
+ "h": 260.28985507246375,
+ "s": 92.82511210762333,
+ "l": 56.27450980392157,
+ "a": 1
+ },
+ "points": [
+ "point-0",
+ "point-1",
+ "point-2"
+ ]
+ },
+ {
+ "id": "poly-1",
+ "color": {
+ "h": 263.27102803738313,
+ "s": 100,
+ "l": 58.03921568627452,
+ "a": 1
+ },
+ "points": [
+ "point-2",
+ "point-1",
+ "point-5"
+ ]
+ },
+ {
+ "id": "poly-2",
+ "color": {
+ "h": 263.4905660377359,
+ "s": 86.88524590163934,
+ "l": 52.156862745098046,
+ "a": 1
+ },
+ "points": [
+ "point-2",
+ "point-5",
+ "point-8"
+ ]
+ },
+ {
+ "id": "poly-3",
+ "color": {
+ "h": 263.3653846153846,
+ "s": 88.88888888888889,
+ "l": 54.11764705882353,
+ "a": 1
+ },
+ "points": [
+ "point-2",
+ "point-8",
+ "point-11"
+ ]
+ },
+ {
+ "id": "poly-4",
+ "color": {
+ "h": 264.82758620689657,
+ "s": 79.6078431372549,
+ "l": 50,
+ "a": 1
+ },
+ "points": [
+ "point-2",
+ "point-11",
+ "point-14"
+ ]
+ },
+ {
+ "id": "poly-5",
+ "color": {
+ "h": 267.192118226601,
+ "s": 100,
+ "l": 39.80392156862745,
+ "a": 1
+ },
+ "points": [
+ "point-11",
+ "point-8",
+ "point-17"
+ ]
+ },
+ {
+ "id": "poly-6",
+ "color": {
+ "h": 266.8421052631579,
+ "s": 100,
+ "l": 37.254901960784316,
+ "a": 1
+ },
+ "points": [
+ "point-11",
+ "point-17",
+ "point-20"
+ ]
+ },
+ {
+ "id": "poly-7",
+ "color": {
+ "h": 267.029702970297,
+ "s": 93.5185185185185,
+ "l": 42.35294117647059,
+ "a": 1
+ },
+ "points": [
+ "point-11",
+ "point-20",
+ "point-14"
+ ]
+ },
+ {
+ "id": "poly-8",
+ "color": {
+ "h": 262.54777070063693,
+ "s": 100,
+ "l": 30.784313725490197,
+ "a": 1
+ },
+ "points": [
+ "point-20",
+ "point-17",
+ "point-26"
+ ]
+ },
+ {
+ "id": "poly-9",
+ "color": {
+ "h": 266.1764705882353,
+ "s": 87.17948717948718,
+ "l": 45.88235294117647,
+ "a": 1
+ },
+ "points": [
+ "point-1",
+ "point-28",
+ "point-5"
+ ]
+ },
+ {
+ "id": "poly-10",
+ "color": {
+ "h": 267.192118226601,
+ "s": 100,
+ "l": 39.80392156862745,
+ "a": 1
+ },
+ "points": [
+ "point-5",
+ "point-28",
+ "point-32"
+ ]
+ },
+ {
+ "id": "poly-11",
+ "color": {
+ "h": 267.029702970297,
+ "s": 93.5185185185185,
+ "l": 42.35294117647059,
+ "a": 1
+ },
+ "points": [
+ "point-5",
+ "point-32",
+ "point-8"
+ ]
+ },
+ {
+ "id": "poly-12",
+ "color": {
+ "h": 264.40677966101697,
+ "s": 100,
+ "l": 34.705882352941174,
+ "a": 1
+ },
+ "points": [
+ "point-8",
+ "point-32",
+ "point-38"
+ ]
+ },
+ {
+ "id": "poly-13",
+ "color": {
+ "h": 260.8,
+ "s": 100,
+ "l": 29.411764705882355,
+ "a": 1
+ },
+ "points": [
+ "point-8",
+ "point-38",
+ "point-41"
+ ]
+ },
+ {
+ "id": "poly-14",
+ "color": {
+ "h": 262.54777070063693,
+ "s": 100,
+ "l": 30.784313725490197,
+ "a": 1
+ },
+ "points": [
+ "point-8",
+ "point-41",
+ "point-17"
+ ]
+ },
+ {
+ "id": "poly-15",
+ "color": {
+ "h": 256.07142857142856,
+ "s": 88.88888888888889,
+ "l": 24.705882352941178,
+ "a": 1
+ },
+ "points": [
+ "point-17",
+ "point-41",
+ "point-47"
+ ]
+ },
+ {
+ "id": "poly-16",
+ "color": {
+ "h": 252.94117647058826,
+ "s": 87.93103448275862,
+ "l": 22.745098039215687,
+ "a": 1
+ },
+ "points": [
+ "point-17",
+ "point-47",
+ "point-26"
+ ]
+ },
+ {
+ "id": "poly-17",
+ "color": {
+ "h": 244.56521739130434,
+ "s": 100,
+ "l": 18.03921568627451,
+ "a": 1
+ },
+ "points": [
+ "point-26",
+ "point-47",
+ "point-53"
+ ]
+ },
+ {
+ "id": "poly-18",
+ "color": {
+ "h": 249.89010989010993,
+ "s": 77.77777777777779,
+ "l": 22.941176470588236,
+ "a": 1
+ },
+ "points": [
+ "point-28",
+ "point-55",
+ "point-32"
+ ]
+ },
+ {
+ "id": "poly-19",
+ "color": {
+ "h": 247.59493670886073,
+ "s": 76.69902912621359,
+ "l": 20.19607843137255,
+ "a": 1
+ },
+ "points": [
+ "point-32",
+ "point-55",
+ "point-59"
+ ]
+ },
+ {
+ "id": "poly-20",
+ "color": {
+ "h": 250.2,
+ "s": 78.12500000000001,
+ "l": 25.098039215686274,
+ "a": 1
+ },
+ "points": [
+ "point-32",
+ "point-59",
+ "point-38"
+ ]
+ },
+ {
+ "id": "poly-21",
+ "color": {
+ "h": 250.12048192771087,
+ "s": 79.04761904761905,
+ "l": 20.58823529411765,
+ "a": 1
+ },
+ "points": [
+ "point-38",
+ "point-59",
+ "point-65"
+ ]
+ },
+ {
+ "id": "poly-22",
+ "color": {
+ "h": 250.00000000000003,
+ "s": 77.99999999999999,
+ "l": 19.607843137254903,
+ "a": 1
+ },
+ "points": [
+ "point-38",
+ "point-65",
+ "point-41"
+ ]
+ },
+ {
+ "id": "poly-23",
+ "color": {
+ "h": 249.79591836734693,
+ "s": 77.77777777777777,
+ "l": 24.705882352941178,
+ "a": 1
+ },
+ "points": [
+ "point-41",
+ "point-65",
+ "point-47"
+ ]
+ },
+ {
+ "id": "poly-24",
+ "color": {
+ "h": 250.54054054054055,
+ "s": 78.72340425531914,
+ "l": 18.43137254901961,
+ "a": 1
+ },
+ "points": [
+ "point-47",
+ "point-65",
+ "point-74"
+ ]
+ },
+ {
+ "id": "poly-25",
+ "color": {
+ "h": 250.74626865671638,
+ "s": 78.82352941176471,
+ "l": 16.666666666666664,
+ "a": 1
+ },
+ "points": [
+ "point-47",
+ "point-74",
+ "point-53"
+ ]
+ },
+ {
+ "id": "poly-26",
+ "color": {
+ "h": 247.01298701298703,
+ "s": 90.58823529411765,
+ "l": 16.666666666666664,
+ "a": 1
+ },
+ "points": [
+ "point-78",
+ "point-79",
+ "point-55"
+ ]
+ },
+ {
+ "id": "poly-27",
+ "color": {
+ "h": 250.1538461538462,
+ "s": 91.54929577464787,
+ "l": 13.92156862745098,
+ "a": 1
+ },
+ "points": [
+ "point-55",
+ "point-79",
+ "point-83"
+ ]
+ },
+ {
+ "id": "poly-28",
+ "color": {
+ "h": 240,
+ "s": 77.77777777777777,
+ "l": 12.352941176470589,
+ "a": 1
+ },
+ "points": [
+ "point-55",
+ "point-83",
+ "point-59"
+ ]
+ },
+ {
+ "id": "poly-29",
+ "color": {
+ "h": 247.24137931034483,
+ "s": 90.62500000000001,
+ "l": 12.549019607843137,
+ "a": 1
+ },
+ "points": [
+ "point-59",
+ "point-83",
+ "point-89"
+ ]
+ },
+ {
+ "id": "poly-30",
+ "color": {
+ "h": 242.53521126760566,
+ "s": 87.65432098765433,
+ "l": 15.88235294117647,
+ "a": 1
+ },
+ "points": [
+ "point-59",
+ "point-89",
+ "point-65"
+ ]
+ },
+ {
+ "id": "poly-31",
+ "color": {
+ "h": 247.63636363636363,
+ "s": 90.16393442622952,
+ "l": 11.960784313725489,
+ "a": 1
+ },
+ "points": [
+ "point-65",
+ "point-89",
+ "point-95"
+ ]
+ },
+ {
+ "id": "poly-32",
+ "color": {
+ "h": 246.25,
+ "s": 88.88888888888887,
+ "l": 10.588235294117649,
+ "a": 1
+ },
+ "points": [
+ "point-65",
+ "point-95",
+ "point-98"
+ ]
+ },
+ {
+ "id": "poly-33",
+ "color": {
+ "h": 240,
+ "s": 87.50000000000001,
+ "l": 9.411764705882353,
+ "a": 1
+ },
+ "points": [
+ "point-98",
+ "point-74",
+ "point-65"
+ ]
+ },
+ {
+ "id": "poly-34",
+ "color": {
+ "h": 250.2,
+ "s": 78.12500000000001,
+ "l": 25.098039215686274,
+ "a": 1
+ },
+ "points": [
+ "point-28",
+ "point-78",
+ "point-55"
+ ]
+ }
+ ]
+};
diff --git a/website/source/javascripts/app/Engine.Particle.Fixed.js b/website/source/javascripts/app/Engine.Particle.Fixed.js
new file mode 100644
index 000000000..164b43057
--- /dev/null
+++ b/website/source/javascripts/app/Engine.Particle.Fixed.js
@@ -0,0 +1,77 @@
+(function(
+ Particle,
+ Engine,
+ Vector
+){
+
+Particle.Fixed = function(width, height){
+ var targetX, targetY;
+
+ this.radius = Engine.getRandomFloat(0.1, 1);
+ // this.fillA = 'rgba(136,67,237,' + Engine.getRandomFloat(0.4, 0.5) + ')';
+ // this.fillB = 'rgba(136,67,237,' + Engine.getRandomFloat(0.51, 0.6) + ')';
+ this.fillA = '#3a1066';
+ this.fillB = '#561799';
+ this.frameMax = Engine.getRandomInt(4, 10);
+
+ this.max = {
+ x: width + this.maxRadius,
+ y: height + this.maxRadius
+ };
+
+ this.min = {
+ x: 0 - this.maxRadius,
+ y: 0 - this.maxRadius
+ };
+
+ targetX = Engine.getRandomInt(0 + this.radius, width + this.radius);
+ targetY = Engine.getRandomInt(0 + this.radius, height + this.radius);
+
+ this.pos = new Vector(targetX, targetY);
+};
+
+Engine.Particle.Fixed.prototype = {
+
+ radius: 1,
+
+ pos: {
+ x: 0,
+ y: 0
+ },
+
+ frame: 0,
+ showA: false,
+
+ update: function(engine){
+ this.frame++;
+ if (this.frame > this.frameMax) {
+ this.frame = 0;
+ this.showA = !this.showA;
+ }
+ return this;
+ },
+
+ draw: function(ctx, scale){
+ // Draw a circle - far less performant
+ ctx.beginPath();
+ ctx.arc(
+ this.pos.x * scale,
+ this.pos.y * scale,
+ this.radius * scale,
+ 0,
+ Math.PI * 2,
+ false
+ );
+ if (this.showA) {
+ ctx.fillStyle = this.fillA;
+ } else {
+ ctx.fillStyle = this.fillB;
+ }
+ ctx.fill();
+
+ return this;
+ }
+
+};
+
+})(window.Engine.Particle, window.Engine, window.Vector);
diff --git a/website/source/javascripts/app/Engine.Particle.js b/website/source/javascripts/app/Engine.Particle.js
new file mode 100644
index 000000000..549f8b4ec
--- /dev/null
+++ b/website/source/javascripts/app/Engine.Particle.js
@@ -0,0 +1,176 @@
+(function(
+ Engine,
+ Vector
+){
+
+Engine.Particle = function(width, height){
+ var side, targetX, targetY;
+ this.accel = Vector.coerce(this.accel);
+ this.vel = Vector.coerce(this.vel);
+ this.pos = new Vector(
+ width / 2,
+ height / 2
+ );
+
+ this.maxRadius = Engine.getRandomFloat(0.1, 2.5);
+ this.maxSpeed = Engine.getRandomFloat(0.01, 1000);
+
+ this.max = {
+ x: width + this.maxRadius,
+ y: height + this.maxRadius
+ };
+
+ this.min = {
+ x: 0 - this.maxRadius,
+ y: 0 - this.maxRadius
+ };
+
+ // Pick a random target
+ side = Engine.getRandomInt(0, 3);
+ if (side === 0 || side === 2) {
+ targetY = (side === 0) ? (0 - this.maxRadius) : (height + this.maxRadius);
+ targetX = Engine.getRandomInt(0 - this.maxRadius, width + this.maxRadius);
+ } else {
+ targetY = Engine.getRandomInt(0 - this.maxRadius, height + this.maxRadius);
+ targetX = (side === 3) ? (0 - this.maxRadius) : (width + this.maxRadius);
+ }
+
+ this.target = new Vector(targetX, targetY);
+ this.maxDistance = this.distanceTo(this.target);
+
+ // this.fillA = 'rgba(136,67,237,' + Engine.getRandomFloat(0.7, 0.8) + ')';
+ // this.fillB = 'rgba(136,67,237,1)';
+ // this.fillA = '#651bb3';
+ // this.fillB = '#9027ff';
+ this.fillA = '#8750c2';
+ this.fillB = '#b976ff';
+ // b976ff
+ this.frameMax = Engine.getRandomInt(1, 5);
+};
+
+Engine.Particle.prototype = {
+
+ radius: 1,
+
+ frame: 0,
+ showA: false,
+
+ accel: {
+ x: 0,
+ y: 0
+ },
+
+ vel: {
+ x: 0,
+ y: 0
+ },
+
+ pos: {
+ x: 0,
+ y: 0
+ },
+
+ opacity: 1,
+
+ maxSpeed: 1500,
+ maxForce: 1500,
+
+ update: function(engine){
+ var distancePercent;
+
+ this.accel.mult(0);
+ this.seek();
+
+ this.vel
+ .add(this.accel)
+ .limit(this.maxSpeed);
+
+ this.pos.add(Vector.mult(this.vel, engine.tick));
+
+ if (
+ this.pos.x < this.min.x ||
+ this.pos.x > this.max.x ||
+ this.pos.y < this.min.y ||
+ this.pos.y > this.max.y
+ ) {
+ this.kill(engine);
+ }
+
+ distancePercent = (this.maxDistance - this.distanceTo(this.target)) / this.maxDistance;
+ this.radius = Math.max(0.1, this.maxRadius * distancePercent);
+
+ this.frame++;
+ if (this.frame > this.frameMax) {
+ this.frame = 0;
+ this.showA = !this.showA;
+ }
+
+ return this;
+ },
+
+ seek: function(){
+ var desired, steer;
+
+ desired = Vector.sub(this.target, this.pos)
+ .normalize()
+ .mult(this.maxSpeed);
+
+ steer = Vector
+ .sub(desired, this.vel)
+ .limit(this.maxForce);
+
+ this.applyForce(steer);
+ },
+
+ draw: function(ctx, scale){
+ if (this.radius < 0.25) {
+ return;
+ }
+
+ if (this.showA) {
+ ctx.fillStyle = this.fillA;
+ } else {
+ ctx.fillStyle = this.fillB;
+ }
+
+ // Draw a square - very performant
+ ctx.fillRect(
+ this.pos.x * scale,
+ this.pos.y * scale,
+ this.radius * scale,
+ this.radius * scale
+ );
+
+ // Draw a circle - far less performant
+ // ctx.beginPath();
+ // ctx.arc(
+ // this.pos.x * scale,
+ // this.pos.y * scale,
+ // this.radius * scale,
+ // 0,
+ // Math.PI * 2,
+ // false
+ // );
+ // ctx.fill();
+
+ return this;
+ },
+
+ applyForce: function(force){
+ this.accel.add(force);
+ return this;
+ },
+
+ kill: function(engine){
+ engine._deferred.push(this);
+ return this;
+ },
+
+ distanceTo: function(target) {
+ var xd = this.pos.x - target.x;
+ var yd = this.pos.y - target.y;
+ return Math.sqrt(xd * xd + yd * yd );
+ }
+};
+
+})(window.Engine, window.Vector);
diff --git a/website/source/javascripts/app/Engine.Point.js b/website/source/javascripts/app/Engine.Point.js
new file mode 100644
index 000000000..66618fc8b
--- /dev/null
+++ b/website/source/javascripts/app/Engine.Point.js
@@ -0,0 +1,88 @@
+(function(
+ Engine,
+ Vector
+){
+
+Engine.Point = function(id, x, y, width, height){
+ this.id = id;
+ this.pos = new Vector(x, y);
+ this.target = this.pos.clone();
+ this.pos.x = width / 2;
+ this.pos.y = height / 2;
+ this.accel = Vector.coerce(this.accel);
+ this.vel = Vector.coerce(this.vel);
+
+ this.pos.add({
+ x: (Engine.getRandomFloat(0, 6) - 3),
+ y: (Engine.getRandomFloat(0, 6) - 3)
+ });
+
+ // Physics randomness
+ // this.stiffness = Engine.getRandomFloat(2, 5);
+ // this.stiffness = Engine.getRandomFloat(0.4, 0.8);
+ this.stiffness = Engine.getRandomFloat(3, 6);
+ this.friction = Engine.getRandomFloat(0.15, 0.3);
+};
+
+Engine.Point.prototype = {
+
+ radius: 1,
+
+ stiffness : 0.5,
+ // friction : 0.00001,
+ friction : 0.01,
+ threshold : 0.03,
+
+ pos: {
+ x: 0,
+ y: 0
+ },
+
+ accel: {
+ x: 0,
+ y: 0
+ },
+
+ vel : {
+ x: 0,
+ y: 0
+ },
+
+ target: {
+ x: 0,
+ y: 0
+ },
+
+ update: function(engine){
+ var newAccel;
+
+ newAccel = Vector.sub(this.target, this.pos)
+ .mult(this.stiffness)
+ .sub(Vector.mult(this.vel, this.friction));
+
+ this.accel.set(newAccel);
+
+ this.vel.add(this.accel);
+
+ this.pos.add(
+ Vector.mult(this.vel, engine.tick)
+ );
+ },
+
+ draw: function(ctx, scale){
+ ctx.beginPath();
+ ctx.arc(
+ this.pos.x * scale,
+ this.pos.y * scale,
+ this.radius * scale,
+ 0,
+ Math.PI * 2,
+ false
+ );
+ ctx.fillStyle = '#ffffff';
+ ctx.fill();
+ }
+
+};
+
+})(window.Engine, window.Vector);
diff --git a/website/source/javascripts/app/Engine.Polygon.js b/website/source/javascripts/app/Engine.Polygon.js
new file mode 100644
index 000000000..819d722ec
--- /dev/null
+++ b/website/source/javascripts/app/Engine.Polygon.js
@@ -0,0 +1,85 @@
+(function(
+ Engine,
+ Vector
+){
+
+Engine.Polygon = function(a, b, c, color){
+ this.a = a;
+ this.b = b;
+ this.c = c;
+
+ this.color = color;
+ this.maxS = this.color.s;
+ this.maxL = this.color.l;
+
+ // this.color.s = 0;
+ this.color.l = 0;
+
+ this.start = Date.now() / 1000;
+
+ this.fillStyle = this.hslaTemplate.substitute(this.color);
+
+ // this.up = !!Engine.getRandomInt(0,1);
+ // this.hueShiftSpeed = 15;
+ // this.toColor = {
+ // a: 1
+ // };
+};
+
+Engine.Polygon.prototype = {
+
+ rgbaTemplate: 'rgba({r},{g},{b},{a})',
+ hslaTemplate: 'hsla({h},{s}%,{l}%,{a})',
+
+ hueShiftSpeed: 20,
+ duration: 3,
+ delay: 2.5,
+
+ // Determine color fill?
+ update: function(engine){
+ var delta;
+
+ delta = engine.now - this.start;
+
+ if (
+ delta > this.delay &&
+ delta < this.delay + this.duration + 1 &&
+ this.color.l < this.maxL
+ ) {
+ // this.color.s = this.maxS * delta / this.duration;
+ this.color.l = this.maxL * (delta - this.delay) / this.duration;
+
+ if (this.color.l > this.maxL) {
+ // this.color.s = this.maxS;
+ this.color.l = this.maxL;
+ }
+
+ this.fillStyle = this.hslaTemplate.substitute(this.color);
+ }
+ },
+
+ draw: function(ctx, scale){
+ ctx.beginPath();
+ ctx.moveTo(
+ this.a.pos.x * scale,
+ this.a.pos.y * scale
+ );
+ ctx.lineTo(
+ this.b.pos.x * scale,
+ this.b.pos.y * scale
+ );
+ ctx.lineTo(
+ this.c.pos.x * scale,
+ this.c.pos.y * scale
+ );
+ ctx.closePath();
+ ctx.fillStyle = this.fillStyle;
+ ctx.lineWidth = 0.25 * scale;
+ ctx.strokeStyle = this.fillStyle;
+ ctx.fill();
+ ctx.stroke();
+ }
+
+};
+
+})(window.Engine, window.Vector);
diff --git a/website/source/javascripts/app/Engine.js b/website/source/javascripts/app/Engine.js
new file mode 100644
index 000000000..8aefd7de3
--- /dev/null
+++ b/website/source/javascripts/app/Engine.js
@@ -0,0 +1,227 @@
+/* jshint unused: false */
+/* global console */
+(function(Base, Vector, Circle){
+
+var sqrt, pow, Engine;
+
+if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ function( callback ){
+ window.setTimeout(callback, 1000 / 60);
+ };
+ })();
+}
+
+sqrt = Math.sqrt;
+pow = Math.pow;
+
+Engine = Base.extend({
+
+ scale: window.devicePixelRatio || 1,
+ // scale:1,
+
+ particles : [],
+ _deferred : [],
+
+ points : [],
+ polygons : [],
+
+ speed: 1,
+ accel: 0.08,
+
+ constructor: function(canvas, bg){
+ var image, el;
+ if (typeof canvas === 'string') {
+ this.canvas = document.getElementById(canvas);
+ } else {
+ this.canvas = canvas;
+ }
+
+ if (!this.canvas.getContext) {
+ return;
+ }
+
+ this.context = this.canvas.getContext('2d');
+
+ this.resize = this.resize.bind(this);
+ this.resize();
+ window.addEventListener('resize', this.resize, false);
+
+ this.setupStarfield(bg);
+ this.setupTessellation();
+
+ this.last = Date.now() / 1000;
+
+ this.start = this.last;
+
+ this.render = this.render.bind(this);
+ this.render();
+
+ this.canvas.style.opacity = 1;
+ /*
+ image = document.getElementById(bg);
+ image.style.webkitTransform = 'translate3d(0,0,0) scale(1)';
+ image.style.opacity = 1;
+ */
+
+ el = document.body;
+
+ setTimeout(function() {
+ el.className += ' state-one';
+ setTimeout(function() {
+ el.className += ' state-two';
+ setTimeout(function() {
+ el.className += ' state-three';
+ setTimeout(function() {
+ el.className += ' state-four';
+ }, 550);
+ }, 200);
+ }, 200);
+ }, 4000);
+ },
+
+ setupStarfield: function(){
+ this.particles = [];
+ this.generateParticles(50, true);
+ this.generateParticles(200);
+ },
+
+ setupTessellation: function(canvas){
+ var row, col, rows, cols, rowMod, colMod, i, p, ref, point, poly;
+
+ ref = {};
+ for (i = 0; i < Circle.Points.length; i++) {
+ point = new Engine.Point(
+ Circle.Points[i].id,
+ Circle.Points[i].x + (this.width / 2 - 180),
+ Circle.Points[i].y + (this.height / 2 - 180),
+ this.width,
+ this.height
+ );
+ ref[point.id] = point;
+ this.points.push(point);
+ }
+
+ for (i = 0; i < Circle.Polygons.length; i++) {
+ poly = Circle.Polygons[i];
+ this.polygons.push(new Engine.Polygon(
+ ref[poly.points[0]],
+ ref[poly.points[1]],
+ ref[poly.points[2]],
+ poly.color
+ ));
+ }
+ },
+
+ render: function(){
+ var tick;
+
+ this.context.clearRect(
+ 0,
+ 0,
+ this.width * this.scale,
+ this.height * this.scale
+ );
+
+ this.now = Date.now() / 1000;
+
+ // if (this.slow) {
+ // this.speed = Math.max(0.1, this.speed - this.accel);
+ // } else {
+ // this.speed = Math.min(1, this.speed + this.accel);
+ // }
+
+ tick = Math.min(this.now - this.last, 0.017);
+ this.tick = this.speed * tick;
+
+ this.renderStarfield(this.now);
+ this.tick = tick;
+
+ if (this.now - this.start > 3) {
+ // this.slow = true;
+ this.renderTessellation(this.now);
+ }
+
+ this.last = this.now;
+
+ window.requestAnimationFrame(this.render);
+ },
+
+ renderTessellation: function(){
+ var scale = this.scale,
+ p;
+
+ for (p = 0; p < this.points.length; p++) {
+ this.points[p].update(this);
+ // this.points[p].draw(this.context, scale);
+ }
+
+ for (p = 0; p < this.polygons.length; p++) {
+ this.polygons[p].update(this);
+ this.polygons[p].draw(this.context, scale);
+ }
+ },
+
+ generateParticles: function(num, fixed){
+ var p;
+
+ for (p = 0; p < num; p++) {
+ if (fixed) {
+ this.particles.push(new Engine.Particle.Fixed(this.width, this.height));
+ } else {
+ this.particles.push(new Engine.Particle(this.width, this.height));
+ }
+ }
+ },
+
+ resize: function(){
+ this.width = window.innerWidth;
+ this.height = 700;
+
+ this.canvas.width = this.width * this.scale;
+ this.canvas.height = this.height * this.scale;
+
+ window.scrollTo(0, 0);
+ },
+
+ renderStarfield: function(){
+ var scale = this.scale, p, index;
+
+ // Update all particles... may need to be optimized
+ for (p = 0; p < this.particles.length; p++) {
+ this.particles[p]
+ .update(this)
+ .draw(this.context, scale);
+ }
+
+ // Remove destroyed entities
+ for (p = 0; p < this._deferred.length; p++) {
+ index = this.particles.indexOf(this._deferred.pop());
+ if (index >= 0) {
+ this.particles.splice(index, 1);
+ }
+ }
+
+ this.generateParticles(600 * this.tick >> 0);
+ }
+
+});
+
+Engine.map = function(val, istart, istop, ostart, ostop) {
+ return ostart + (ostop - ostart) * ((val - istart) / (istop - istart));
+};
+
+Engine.getRandomFloat = function(min, max) {
+ return Math.random() * (max - min) + min;
+};
+
+Engine.getRandomInt = function(min, max) {
+ return Math.floor(Math.random() * (max - min + 1) + min);
+};
+
+window.Engine = Engine;
+
+})(window.Base, window.Vector, window.Circle);
diff --git a/website/source/javascripts/app/Init.js b/website/source/javascripts/app/Init.js
new file mode 100644
index 000000000..89b455fb0
--- /dev/null
+++ b/website/source/javascripts/app/Init.js
@@ -0,0 +1,36 @@
+(function(
+ Engine
+){
+
+var Init = {
+
+ start: function(){
+ var id = document.body.id.toLowerCase();
+
+ if (this.Pages[id]) {
+ this.Pages[id]();
+ }
+ },
+
+ Pages: {
+ 'page-home': function(){
+ var jumbotron = document.getElementById('jumbotron'),
+ canvas;
+
+ if (!jumbotron) {
+ return;
+ }
+
+ canvas = document.createElement('canvas');
+ canvas.className = 'terraform-canvas';
+
+ jumbotron.appendChild(canvas);
+ window.engine = new Engine(canvas, 'image');
+ }
+ }
+
+};
+
+Init.start();
+
+})(window.Engine);
diff --git a/website/source/javascripts/app/Puller.js b/website/source/javascripts/app/Puller.js
new file mode 100644
index 000000000..2df85c733
--- /dev/null
+++ b/website/source/javascripts/app/Puller.js
@@ -0,0 +1,136 @@
+(function(
+ Engine,
+ Vector
+){
+
+var Puller = function(x, y){
+ this.pos.x = x;
+ this.pos.y = y;
+ this.pos = Vector.coerce(this.pos);
+ this.home = this.pos.clone();
+ this.accel = Vector.coerce(this.accel);
+ this.vel = Vector.coerce(this.vel);
+};
+
+Puller.prototype = {
+
+ fillStyle: '#ffffff',
+ radius: 5,
+
+ maxSpeed: 160,
+ maxForce: 50,
+
+ pos: {
+ x: 0,
+ y: 0
+ },
+
+ accel: {
+ x: 0,
+ y: 0
+ },
+
+ vel: {
+ x: 0,
+ y: 0
+ },
+
+ aRad: 200,
+
+ safety: 0.25,
+
+ update: function(engine){
+ var distanceToMouse = this.distanceTo(engine.mouse),
+ toHome, mag, safety;
+ // distanceToHome = this.distanceTo(this.home);
+
+ this.accel.mult(0);
+
+ if (distanceToMouse < this.aRad) {
+ this.toChase(engine.mouse);
+ }
+
+ this.toChase(this.home, this.maxForce / 2);
+
+ this.vel.add(this.accel);
+ this.pos.add(
+ Vector.mult(this.vel, engine.tick)
+ );
+
+ toHome = Vector.sub(this.home, this.pos);
+ mag = toHome.mag();
+ safety = this.aRad * (this.safety * 3);
+ if (mag > this.aRad - safety) {
+ toHome.normalize();
+ toHome.mult(this.aRad - safety);
+ this.pos = Vector.sub(this.home, toHome);
+ }
+ },
+
+ toChase: function(target, maxForce){
+ var desired, steer, distance, mult, safety;
+
+ maxForce = maxForce || this.maxForce;
+
+ target = Vector.coerce(target);
+ desired = Vector.sub(target, this.pos);
+ distance = desired.mag();
+ desired.normalize();
+
+ safety = this.aRad * this.safety;
+
+ if (distance < safety) {
+ mult = Engine.map(distance, 0, safety, 0, this.maxSpeed);
+ } else if (distance > this.aRad - safety){
+ mult = Engine.map(this.aRad - distance, 0, safety, 0, this.maxSpeed);
+ } else {
+ mult = this.maxSpeed;
+ }
+
+ desired.mult(mult);
+
+ steer = Vector.sub(desired, this.vel);
+ steer.limit(maxForce);
+ this.accel.add(steer);
+ },
+
+ draw: function(ctx, scale){
+ // ctx.beginPath();
+ // ctx.arc(
+ // this.home.x * scale,
+ // this.home.y * scale,
+ // this.aRad * scale,
+ // 0,
+ // Math.PI * 2,
+ // false
+ // );
+ // ctx.fillStyle = 'rgba(255,255,255,0.1)';
+ // ctx.fill();
+
+ ctx.beginPath();
+ ctx.arc(
+ this.pos.x * scale,
+ this.pos.y * scale,
+ this.radius * scale,
+ 0,
+ Math.PI * 2,
+ false
+ );
+ ctx.fillStyle = this.fillStyle;
+ ctx.fill();
+
+ },
+
+ distanceTo: function(target) {
+ var xd = this.home.x - target.x;
+ var yd = this.home.y - target.y;
+ return Math.sqrt(xd * xd + yd * yd );
+ }
+};
+
+window.Puller = Puller;
+
+})(
+ window.Engine,
+ window.Vector
+);
diff --git a/website/source/layouts/_footer.erb b/website/source/layouts/_footer.erb
index 71280c244..3df1589fa 100644
--- a/website/source/layouts/_footer.erb
+++ b/website/source/layouts/_footer.erb
@@ -19,5 +19,19 @@