Tutorial

Overview

move()

The core of Ayva's Motion API is the move() method. The move() method takes an arbitrary number of arguments, each of which is an object describing the motion along a single axis. The simplest description is just a target position and speed:

ayva.move({
  axis: 'stroke', // The axis to move.
  to: 0,          // Target position in normalized units [0 - 1].
  speed: 1        // Speed in units per second.
});

This command tells Ayva to move the stroke axis (L0 in the default configuration) to the bottom of its range (position 0) with an average speed of 1 unit per second. A unit in this context is the full length of the range of the axis. Therefore, another way to interpret speed is strokes per second.

Try it out!

Alternatively, a duration for the move can be specified:

ayva.move({
  axis: 'stroke',
  to: 1,    
  duration: 1,   // Duration of the move in seconds
});

This command tells Ayva to move the stroke axis to the top of its range (position 1) over the course of one second.

Try it out!

These examples could be viewed as somewhat analagous to speed and interval commands in TCode (ex: L000S100 or L099I1000, respectively). However, internally Ayva uses live updates when generating TCode. This allows for movement shapes that are not linear. As you may have been able to tell from the examples, the default ramp (shape of the motion) used by Ayva is actually a cosine wave. Later, we will discuss how to change this behavior.

Default Axis

In the examples shown so far we have explicitly set the axis to stroke. In the default configuration, the stroke axis is actually the default axis, so we didn't really have to specify it in those cases. i.e.

ayva.move({
  to: 0,
  speed: 1
});

or

ayva.move({
  to: 1,    
  duration: 1,
});

would also have worked, respectively. This can be changed by setting the defaultAxis property.

ayva.defaultAxis = 'twist';

Alternatively, the default axis can be specified when creating a configuration.

Asynchronous Movement

The move() method is asynchronous. It returns a Promise that resolves when the move is finished. If you need to execute code only after a move is done, you can use Promise chaining:

ayva.move({ to: 0, speed: 1 }).then(() => {
  console.log('The move is complete!')
});

Or you can use the await keyword inside of an async function:

async function myStroke() {
  await ayva.move({ to: 0, speed: 1 });
  console.log('The move is complete!');
}

myStroke();

Move Queue

Internally, Ayva uses a queue to keep track of moves. If a move is already in progress when move() is called, the requested move is added to the queue and will not execute until all preceding moves have finished. So while move() is asynchronous, all moves are guaranteed to execute in the order they were called. The following example illustrates this:

// Perform a few down and up strokes (with up strokes performed at half speed).
ayva.move({ to: 0, speed: 1 });
ayva.move({ to: 1, speed: 0.5 });
ayva.move({ to: 0, speed: 1 });
ayva.move({ to: 1, speed: 0.5 }).then(() => {
  // The following line will not execute until all moves have finished.
  console.log('Finished all strokes!');
});

// Because move() is asynchronous, the following line executes before the moves have finished.
console.log('Stroking...');

Try it out!

In this example, if you open the Developer Tools in your browser while running, you should see the text "Stroking..." print to the console first, and then when all strokes have finished you should see the text "Finished all strokes!" print.

Stopping

The stop() method can be called to stop all movements (running or pending). The following example demonstrates stop() by creating a button that the user can click to stop the movement:

// Create a large stop button positioned towards the top right.
const stopButton = document.createElement('button');
stopButton.textContent = 'Click to Stop!';
stopButton.style.fontSize = '32px';
stopButton.style.position = 'absolute';
stopButton.style.top = '50px';
stopButton.style.right = '50px';
document.body.appendChild(stopButton);

// Call stop() when the button is clicked.
stopButton.addEventListener('click', () => ayva.stop());

// Start a long running move (10 seconds).
ayva.move({ to: 1, duration: 10 }).then((complete) => {
  // Note: A move's Promise resolves with the value true if the move completed successfully, false otherwise.
  if (!complete) {
    console.log('The move was stopped before it finished.');
  } else {
    console.log('The move completed successfully.');
  }
});

Try it out!

In this example, if you open the Developer Tools in your browser while running and you click the stop button before the move finishes, you should see the message "The move was stopped before it finished." print. If you do not click the stop button and instead let the move finish you should see "The move completed successfully."

Default Ramp

The default ramp can be changed by setting the defaultRamp property on an instance of Ayva. There are four built-in ramp types available as static properties of the Ayva class:

Cosine

ayva.defaultRamp = Ayva.RAMP_COS;

Try it out!

Linear

ayva.defaultRamp = Ayva.RAMP_LINEAR;

Try it out!

Parabolic

ayva.defaultRamp = Ayva.RAMP_PARABOLIC;

Try it out!

Negative Parabolic

ayva.defaultRamp = Ayva.RAMP_NEGATIVE_PARABOLIC

Try it out!

You can also supply your own ramp function. The default ramp is actually a value provider, and how to create one will be covered in the next section.