diff --git a/demo/index.html b/demo/index.html
index 880edac..e248179 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -44,6 +44,7 @@
+
diff --git a/demo/js/Demo.js b/demo/js/Demo.js
index 014bb6e..4a7a498 100644
--- a/demo/js/Demo.js
+++ b/demo/js/Demo.js
@@ -118,6 +118,12 @@
init: Example.concave,
sourceLink: sourceLinkRoot + '/concave.js'
},
+ {
+ name: 'Double Pendulum',
+ id: 'doublePendulum',
+ init: Example.doublePendulum,
+ sourceLink: sourceLinkRoot + '/doublePendulum.js'
+ },
{
name: 'Events',
id: 'events',
diff --git a/examples/doublePendulum.js b/examples/doublePendulum.js
new file mode 100644
index 0000000..bef6958
--- /dev/null
+++ b/examples/doublePendulum.js
@@ -0,0 +1,151 @@
+var Example = Example || {};
+
+Example.doublePendulum = function() {
+ var Engine = Matter.Engine,
+ Events = Matter.Events,
+ Render = Matter.Render,
+ Runner = Matter.Runner,
+ Body = Matter.Body,
+ Composite = Matter.Composite,
+ Composites = Matter.Composites,
+ Constraint = Matter.Constraint,
+ MouseConstraint = Matter.MouseConstraint,
+ Mouse = Matter.Mouse,
+ World = Matter.World,
+ Bodies = Matter.Bodies,
+ Vector = Matter.Vector;
+
+ // create engine
+ var engine = Engine.create(),
+ world = engine.world;
+
+ // create renderer
+ var render = Render.create({
+ element: document.body,
+ engine: engine,
+ options: {
+ width: Math.min(document.documentElement.clientWidth, 800),
+ height: Math.min(document.documentElement.clientHeight, 600),
+ wireframes: false,
+ background: '#0f0f13'
+ }
+ });
+
+ Render.run(render);
+
+ // create runner
+ var runner = Runner.create();
+ Runner.run(runner, engine);
+
+ // add bodies
+ var group = Body.nextGroup(true),
+ length = 200,
+ width = 25;
+
+ var pendulum = Composites.stack(350, 160, 2, 1, 0, 0, function(x, y) {
+ return Bodies.rectangle(x, y, length, width, {
+ collisionFilter: { group: group },
+ frictionAir: 0,
+ chamfer: 5,
+ render: {
+ fillStyle: 'transparent',
+ lineWidth: 1
+ }
+ });
+ });
+
+ pendulum.bodies[0].render.strokeStyle = '#4a485b';
+ pendulum.bodies[1].render.strokeStyle = '#4a485b';
+
+ Composites.chain(pendulum, 0.5, 0, -0.5, 0, {
+ stiffness: 1,
+ length: 0,
+ angularStiffness: 0.7,
+ render: {
+ lineWidth: 0
+ }
+ });
+
+ Composite.add(pendulum, Constraint.create({
+ bodyB: pendulum.bodies[0],
+ pointB: { x: -length * 0.5, y: 0 },
+ pointA: { x: pendulum.bodies[0].position.x - length * 0.5, y: pendulum.bodies[0].position.y },
+ stiffness: 1,
+ length: 0,
+ render: {
+ lineWidth: 0
+ }
+ }));
+
+ var lowerArm = pendulum.bodies[1];
+
+ Body.rotate(lowerArm, -Math.PI * 0.3, {
+ x: lowerArm.position.x - 100,
+ y: lowerArm.position.y
+ });
+
+ World.add(world, pendulum);
+
+ var trail = [];
+
+ Events.on(render, 'afterRender', function() {
+ trail.unshift({
+ position: Vector.clone(lowerArm.position),
+ speed: lowerArm.speed
+ });
+
+ Render.startViewTransform(render);
+ render.context.globalAlpha = 0.7;
+
+ for (var i = 0; i < trail.length; i += 1) {
+ var point = trail[i].position,
+ speed = trail[i].speed;
+
+ var hue = 250 + Math.round((1 - Math.min(1, speed / 10)) * 170);
+ render.context.fillStyle = 'hsl(' + hue + ', 100%, 55%)';
+ render.context.fillRect(point.x, point.y, 2, 2);
+ }
+
+ render.context.globalAlpha = 1;
+ Render.endViewTransform(render);
+
+ if (trail.length > 2000) {
+ trail.pop();
+ }
+ });
+
+ // add mouse control
+ var mouse = Mouse.create(render.canvas),
+ mouseConstraint = MouseConstraint.create(engine, {
+ mouse: mouse,
+ constraint: {
+ stiffness: 0.2,
+ render: {
+ visible: false
+ }
+ }
+ });
+
+ World.add(world, mouseConstraint);
+
+ // keep the mouse in sync with rendering
+ render.mouse = mouse;
+
+ // fit the render viewport to the scene
+ Render.lookAt(render, {
+ min: { x: 0, y: 0 },
+ max: { x: 700, y: 600 }
+ });
+
+ // context for MatterTools.Demo
+ return {
+ engine: engine,
+ runner: runner,
+ render: render,
+ canvas: render.canvas,
+ stop: function() {
+ Matter.Render.stop(render);
+ Matter.Runner.stop(runner);
+ }
+ };
+};
\ No newline at end of file