Return to the VisualSpinner3D main site.

VisualSpinner3D "under the hood."

The VisualSpinner3D engine is a complicated beast. This page – hopefully an evolving essay – aims to explain what's going on under the hood, in technical detail that may be of interest to both tech spinners and programmers. This model should probably be considered an extension or modification of Charlie Cushing's QFT model, and was also influenced by videos and articles from Ben Drexler.

The heart of VisualSpinner3D consists of two types of things: props and moves.

Props:

The VS3D model treats all props – be they poi, staves, hoops, et cetera – as identical, except for how they look. The most important thing we need to know about a prop is where it is. How do we model that? A poi has a handle, a head, and a tether that connects the handle to the head. Many other props, even ones that don't have "heads" per se, can be thought of in the same way. For example, a hoop's "handle" might be the place where you grip it, and its "head" might be the opposite end.

So if we want to know where a prop is, we need to know where its handle is and where its head is. To model that in three dimensions, we could use familiar X, Y, and Z coordinates. For VisualSpinner3D, however, I chose to use a system related to spherical or horizontal coordinates instead. Why? Because these coordinate systems work very smoothly for modeling things that tend to travel in circular paths, like planets or, in this case, props. Specifically, the positions of each part of a prop are defined by a radius - a distance from some other point - an angle - degrees of rotation along the wall or wheel planes from straight up - and a bearing - degrees of rotation around the floor plane.

Usually, when a prop moves, both the handle and the head move. We can avoid some extra hassle by measuring the head's position relative to the handle – that is, we measure the handle's angle and distance from the origin, and then we measure the head's angle and distance away from the handle. That way, when the handle moves, the head will always move along with it. And instead of modeling a flower as a complicated, trigonometric cycloid, we can think of it in a more intuitive way – a circular hand path combined with a circular prop path.

We could stop there – any prop could be defined strictly in terms of a hand position and a head position – but in many cases, it's helpful to have more coordinates. For example, if we want to model someone walking while they spin a prop, do we want to model the hand path as a cycloid? Or, what if we want to model a move pivoted slightly to one side – wouldn't it be easier to think of this as pivoting in a straight line followed by spinning in a circle, rather than a complicated equation for a displaced circle? In general, it's going to be easier and more intuitive to split these complicated motions into a larger number of simple parts, rather than trying to tie everything together into one, huge equation.

Through trial and error, I found that it's most convenient to model a prop as consisting of no more than six "nodes":

body: shall we imagine that the spinner is walking around?
  →pivot: shall we imagine that the spinner is shifting from side to side?
    →helper: used for adjusting the move in complex ways.
      →hand: where is the handle of the prop?
        →grip: at what angle does the spinner hold the prop?
          →head: the head of a poi, or the designated end of a staff.

The head is positioned relative to the grip, which is positioned relative to the handle; the handle relative to the helper, the helper relative to the pivot, and the pivot relative to body; which is itself relative to the origin. There is one final element - the "twist" of the prop's grip, which is irrelevant for poi or staves, but visually interesting on props with a flat axis of symmetry, like hoops or fans.

A prop extended one arm's length up from the origin is defined like so:

{
  body: { r: 0, a: 0, b: 0 },
  pivot: { r: 0, a: 0, b: 0 },
  helper: {r: 0, a: 0, b: 0 },
  hand: { r: 1, a: 0, b: 0 },
  grip: { r: 0, a: 0, b: 0 },
  head: { r: 1, a: 0, b: 0 },
  twist: 0
}

Using these "recursive spherical coordinates," it is possible to model almost any prop movement as a simple combination of linear and circular motions.

We can make the model even more flexible by adding a few "extra" coordinates: bent and twist. "Twist" represents rotating the prop around its own axis – irrelevant for poi or staff, but visually interesting for hoops and fans. Bent rotates the prop away from its own axis of motion. This makes modeling plane-bent movements, such as toroids and weaves, much cleaner.

Moves:

Props aren't very exciting when they stand still. Moves in VS3D, much like props, are modeled as a series of nodes - the prop's handle might move, its head might move, and so on. But while a prop can be positioned anywhere in three-dimensional space, a move typically place in a single two-dimensional plane. Accordingly, movements are in terms of a radius, an angle, and a plane.

Each node's radius and angle can have a position, velocity, and acceleration, and a plane. The twist can also have a position and velocity, and a final parameter, called "bent", is used to model plane-bent movements. The duration of a movemenet is measured in "beats", which is an arbitrary measurement of how long it takes a prop to complete a quarter of a spin. A four-petal in-spin flower is modeled like so:

{
  hand: {va: 1},
  head: {va: 4}
}

The engine by default assumes that anything you didn't specify - for example, the body, pivot, helper, and grip nodes in this movement - are zero, and the starting radius and angle are based on the prop that's spun.

Sequences of movements are represented simply by putting multiple moves in an array. VS3D has a variety of solving algorithms that help make sure moves fit together smoothly.

Recipes:

Even though we could combine movements into chunks of any size, spinners often thing of them not in terms of rotations of hands and head, but rather of "moves" or "tricks" with special names, which could have many variants. For example, a four-petal anti-spin flower can be spun with many different orientations, in different planes, in diamond or box mode, and so on. VS3D uses "recipes" to build full-fledged movements out of the options you supply.

Recipes look something like this:

{
 recipe: "flower",
 direction: CLOCKWISE,
 spin: ANTISPIN,
 petals: 4,
 mode: DIAMOND,
 plane: WALL
});

Using recipes, you can generate complex "quintuple spherical" movements using keywords that make sense to spinners. (You don't have to provide every option; for example, direction defaults to CLOCKWISE and plane defaults to WALL.)

Code:

VisualSpinner3D is written in JavaScript and consists of three scripts: vs3d.js, vs3d-moves.js, and vs3d-render.js.

The vs3d.js script defines the rules for how Props and Moves work, implementer-friendly wrappers to make them work together, the geometrical helper methods for encoding circular and linear motions, and the tools for importing and exporting JSON definitions. It also contains a variety of useful constants, with names like CLOCKWISE, OPPOSITE, ANTISPIN, and so on, that translate spinning concepts into mathematical parameters (CLOCKWISE equals 1, ANTISPIN equals -1, and OPPOSITE equals 2Π radians.)

The vs3d-moves.js script defines all built-in recipes: flowers, CAPs, pendulums, and so on.

The ui.js script defines the HTML5Canvas2dRenderer and the Phoria3dRenderer, which use two different graphics engines to animate props in either 2D or 3D. It also defines a VisualSpinnerWidget that embeds a customizable VisualSpinner3D GUI element into a website.

A page that incorporates VisualSpinner3D needs a /scripts directory and should include the following code:

<script>src="scripts/visual-spinner-engine.js"></script>
<script>src="scripts/visual-spinner-moves.js"></script>
<script>src="scripts/visual-spinner-ui.js"></script>

The root JavaScript object of the VisualSpinner3D engine is called VS3D. A new widget can be created like so:

var vs = VS3D.VisualSpinnerWidget();
vs.embedById("theIdTagOfSomeDivOnMyPage");
vs.addControls("play","pause","rewind","frame","forward","reset","2d3d");

Props and moves can be added like so:

var myProp = vs.addProp();
myProp.color = "orange";
myProp.addMove(VS3D.moves.build.flower({direction: VS3D.COUNTERCLOCKWISE, petals: 3, spin: VS3D.ANTISPIN}); myProp.addMove(VS3D.moves.build.pendulum({speed: 2, duration: 0.25});

Or, you can add directly from a JSON file — perhaps one you exported from the composer:

vs.parseFile("mysavedroutine.json");

(As described earlier, in most cases the Prop.addMove method will automatically reorient the new move to match the ending socket of the existing list of moves.)

By default, the widget allows playback of a pre-specified sequenced of moves. More advanced functionality, including menus, drag-and-drop, and other features seen on the various pages of this site, require custom JavaScript and fuller understanding of the VisualSpinner3D code base.


Known Bugs:

Note a few limitations of this model:

Also note that this is not the only way prop movements can be formally modeled. You may have seen Ben Drexler, among others, model props using trigonometric functions parameterized with respect to time, using Cartesian coordinates. That approach is mathematically elegant for modeling flowers and certain other moves, but I found that it becomes unwieldy when modeling more general prop movements.