Hello, World

Install the library

Or with npm:

npm install --save newton
var Newton = require('newton');

Create a simulation

The Simulator is responsible for integrating Particles, applying Forces, and resolving Constraints.

All the high-level and advanced functionality of Newton is based on these three simple steps.

var sim = Newton.Simulator();
sim.start();

Add a particle

Newton has three building blocks: Particles, Forces, and Constraints. Particles are points in space that have X and Y coordinates as well as mass (size).

var particle = Newton.Particle(10, 20);  // x, y
sim.add(particle);

Render the scene

Newton ships with a WebGL-based renderer for development and debugging. To use it, you'll need to create a canvas element on your page. In this case, we've called our canvas `#display`.

You can render anyway you like - canvas, webgl, DOM, SVG, etc. All renderers support a simple interface.

var display = document.getElementById('display');
var renderer = Newton.GLRenderer(display);
renderer.render(sim);

Demo: Hello, World

As you can see, we're up and running - but it's a little boring with just one Particle sitting still.

Movement

Forces

Forces are the second basic element of Newton. Each frame, the Simulator applies Forces to Particles in order to create movement.

Newton comes with a library of Forces, and you can easily add your own.

var gravity = Newton.LinearForce(1, Math.PI * 1.5);   // strength, direction
sim.add(gravity);

Constraints

Constraints are the third basic element of Newton and are its most powerful feature.

They create rules that are applied to Particles after integration, like "All particles should stay within this rectangle," or "These two particles should be connected."

BoxConstraint is a location constraint that keeps a particle within a rectangular area. Newton comes with a library of Constraints.

var container = Newton.BoxConstraint(0, 0, 1000, 600);   // x, y, width, height
sim.add(container);

The simulator runs constraints repeatedly to converge at an approximate solution. Since constraints can conflict with each other, it's a good idea to give Newton a hint about which constraints are most important. You can do this via the Simulator's solve option:

var sim = Newton.Simulator({
  solve: [ Newton.PinConstraint, Newton.RopeConstraint ]  // PinConstraint is more important than RopeConstraint
});

Demo: Rope

Now things are getting interesting. Our little rope has come to life!

Bodies

Create a Body

When building a simulation, you frequently want to refer to a group of Particles, Forces, and Constraints as a single entity. Newton uses the concept of Bodies for grouping elements.

Instead of adding Particles and Constraints directly to the Simulator, we can instead add them as a group in a Body:

var rope = Newton.Body();

rope.add(Newton.Particle(500 + i * 20, 180));
rope.add(Newton.RopeConstraint(prev, current));

sim.add(rope);

Keep in mind, Bodies are just for bookkeeping - logical groupings so your code can be readable. They have no impact on the simulation.

Extending Body

In most cases, you'll extend Newton's base Body to create reusable custom Body types. For example, let's create a Rope Body:

function Rope(x, y, length) {
  Newton.Body.call(this);   // call Body's constructor
  
  // implementation here
}

Rope.prototype = Object.create(Newton.Body.prototype);  // extend Body's prototype

var rope = new Rope(225, 10, 300);

Demo: Rope Body

Reuse! We now have a drop-in Rope Body that we can use as many times as we like:

We can also extend Rope with new data and behaviors. We've already given it a head property - we could also add a tail property or methods like coil() or snap()

Interaction

Input

Interacting with Newton is easy - just inject Forces, Particles, or Constraints into the system based on your user's behavior.

var mousePin = null;

renderer.on('pointerdown', function(point) {
    var particle = sim.findNearest(point, 30);
    if (particle) mousePin = sim.add(Newton.PinConstraint(particle, point));
});

In this case, we've added a PinConstraint to represent the user. When the user clicks on a Particle, we bind the Particle to a new constraint, which we update to follow wherever the user moves her mouse.

Removal

Just like add() adds Particles, Forces, and Constraints to a simulation, remove() removes them.

In this case, we want to remove the PinConstraint whenever the user releases her mouse, so she can "let go" of the dragged Particle:

renderer.on('pointerup', function(point) {
   if (!mousePin) return;
   sim.remove(mousePin);
   mousePin = null;
});

Destruction

Some Constraints can receive options that include some sort of strength value. If a Simulation reaches a point where the Constraint is acting beyond its strength, it will destroy itself to create realistic deformations and structural behavior.

RopeConstraints can have a tensile strength. Here, we specify that once the Constraint stretches to 3x its original length, it should break:

this.add(Newton.RopeConstraint(prev, current, {
    length: segmentLength,
    stiffness: 0.9,         // slightly springy
    strength: 3             // break when stretched to 3x length
} ));

Demo: Interactive Rope

Now we can drag our ropes around! If we stretch them too far they'll even realistically break.