diff --git a/.tern-project b/.tern-project
new file mode 100644
index 0000000..31aa749
--- /dev/null
+++ b/.tern-project
@@ -0,0 +1,6 @@
+{
+ "ecmaVersion": 6,
+ "libs": [
+ "browser"
+ ]
+}
\ No newline at end of file
diff --git a/Bicycle.js b/Bicycle.js
new file mode 100644
index 0000000..967ec05
--- /dev/null
+++ b/Bicycle.js
@@ -0,0 +1,124 @@
+"use strict";
+
+class Bicycle
+{
+ constructor(inPos)
+ {
+ this.pos = inPos;
+
+ this.wheelLeft = new Wheel(new Vector(-47, 20), 30, 200);
+ this.wheelRight = new Wheel(new Vector(47, 20), 30, 200);
+
+ this.mainColour = "#4f32d2";
+ this.seatColour = "#312b50";
+ this.seatSize = 10;
+ }
+
+ update(dt)
+ {
+ this.wheelLeft.update(dt);
+ this.wheelRight.update(dt);
+ }
+
+ render(context)
+ {
+ context.save();
+ context.translate(this.pos.x, this.pos.y);
+
+ this.wheelLeft.render(context);
+ this.wheelRight.render(context);
+
+ // Bicycle frame
+ var pedalPosition = this.wheelRight.pos.clone().subtract(new Vector(35, 0)),
+ seatPosition = pedalPosition.clone().add(new Vector(15, -40));
+ context.beginPath();
+ context.moveTo(this.wheelLeft.pos.x, this.wheelLeft.pos.y);
+ context.lineTo(this.wheelLeft.pos.x + 20, this.wheelLeft.pos.y - 52);
+ context.moveTo(this.wheelLeft.pos.x + 13, this.wheelLeft.pos.y - 35);
+ context.lineTo(pedalPosition.x, pedalPosition.y);
+ context.lineTo(seatPosition.x, seatPosition.y);
+ context.moveTo(pedalPosition.x, pedalPosition.y);
+ context.lineTo(this.wheelRight.pos.x, this.wheelRight.pos.y);
+ context.lineTo(seatPosition.x - 4, seatPosition.y + 10);
+ context.lineTo(this.wheelLeft.pos.x + 14, this.wheelLeft.pos.y - 40);
+
+ context.lineWidth = 5;
+ context.strokeStyle = this.mainColour;
+ context.stroke();
+
+ this.renderSeat(context, seatPosition);
+
+ context.restore();
+ }
+
+ renderSeat(context, pos)
+ {
+ context.save();
+ context.translate(pos.x - this.seatSize * 0.3, pos.y);
+ context.beginPath();
+ context.moveTo(this.seatSize, -this.seatSize / 2.4);
+ context.lineTo(-this.seatSize * 1.5, 0);
+ context.lineTo(this.seatSize * 1.3, this.seatSize / 2.3);
+ context.closePath();
+
+ context.fillStyle = this.seatColour;
+ context.fill();
+
+ context.restore();
+ }
+}
+
+class Wheel
+{
+ constructor(inPos, inRadius, inSpeed)
+ {
+ this.pos = inPos;
+ this.radius = inRadius;
+ this.speed = inSpeed / (Math.PI * 18);
+
+ this.rotation = 0;
+
+ this.rimColour = "#1f1e1e";
+ this.spokeColour = "rgb(198, 176, 172)";
+ this.spokeCount = 12;
+
+ this.spokeSpacing = (Math.PI*2) / this.spokeCount;
+ }
+
+ update(dt)
+ {
+ this.rotation -= this.speed * dt;
+ }
+
+ render(context)
+ {
+ context.save();
+ context.translate(this.pos.x, this.pos.y);
+ context.rotate(this.rotation);
+
+ context.beginPath();
+ for (let r = 0; r < Math.PI; r += this.spokeSpacing)
+ {
+ context.moveTo(this.radius * Math.cos(r), this.radius * Math.sin(r));
+ context.lineTo(this.radius * Math.cos(r + Math.PI), this.radius * Math.sin(r + Math.PI));
+ }
+
+ context.lineWidth = 1;
+ context.strokeStyle = this.spokeColour;
+ context.stroke();
+
+ context.beginPath();
+ context.ellipse(0, 0, this.radius * 0.95, this.radius * 0.95, 0, 0, Math.PI * 2, false);
+ context.lineWidth = 3;
+ context.stroke();
+
+ context.beginPath();
+ context.ellipse(0, 0, this.radius, this.radius, 0, 0, Math.PI * 2, false);
+
+ context.strokeStyle = this.rimColour;
+ context.lineWidth = 4;
+ context.stroke();
+
+ context.restore();
+ }
+}
diff --git a/Road.js b/Road.js
index b458799..44be044 100644
--- a/Road.js
+++ b/Road.js
@@ -28,8 +28,8 @@ class Road
context.fillRect(0, 0, this.size.x, this.size.y);
context.beginPath();
- context.moveTo(0, this.size.y / 2.1);
- context.lineTo(this.size.x, this.size.y / 2.1);
+ context.moveTo(0, this.size.y / 2.2);
+ context.lineTo(this.size.x, this.size.y / 2.2);
context.lineWidth = 5;
context.setLineDash([35, 20]);
diff --git a/index.html b/index.html
index 0d8d480..17fda29 100644
--- a/index.html
+++ b/index.html
@@ -19,5 +19,6 @@
+