Scripting fundamentals

Graphic primitives

All of the primitive shapes that can be exported in Cuttle are called Graphics. There are four Graphic classes:

  • An Anchor represents an anchor point of a Path. It has a .position.handleIn, and .handleOut property (all Vecs).
  • Path represents an arbitrary closed or open path. It has an .anchors property which is an array of Anchors and a .closed property which is true or false. It also has Style properties .fill and .stroke.
  • CompoundPath represents a collection of paths. These are used to create shapes with holes. You can also use these to “bundle” together multiple paths which can be useful in certain export situations (e.g. to force certain machines to trace those paths in order). A CompoundPath has a .paths property. It also has Style properties .fill and .stroke.
  • Group is an organizational unit. It has an .items property which is an array of other Graphics.

Constructors

Here’s an example showing how to create each primitive. You can try pasting this code as a new Code Component.

// Anchors created with position, handleIn, and handleOut. // Note: handleIn and handleOut are relative values from position. const a1 = Anchor(Vec(2, 0), Vec(0, 0), Vec(0.5, 0)); const a2 = Anchor(Vec(3, 1), Vec(-0.5, 0), Vec(0, 0)); // Creating a Path from the above anchors. By default Paths are // not closed. const path1 = Path([a1, a2]); // Putting `true` as the second argument to Path() makes a closed // path. const path2 = Path( [Anchor(Vec(2, 2)), Anchor(Vec(2, 5)), Anchor(Vec(5, 5)), Anchor(Vec(5, 2))], true ); // Using Path.fromPoints(...) is another way to create a Path from // straight segments. const path3 = Path.fromPoints([Vec(3, 3), Vec(3, 4), Vec(4, 4)], true); // Creating a CompoundPath const compoundPath = CompoundPath([path2, path3]); // Creating a Group const group = Group([path1, compoundPath]); return group;

Note that typing new before the constructors is optional.

The code above also demonstrates Path.fromPoints(...) to construct a Path of straight segments. You can find more convenience methods for creating Anchors, Paths, CompoundPaths, and Groups in the reference documentation.

Navigating the scene hierarchy

Graphics form a tree and that tree can be arbitrarily nested — Groups can contain other Groups. When writing modifiers, it’s often handy to just work with all the Anchors or all the Paths. Thus there are convenience methods that will traverse through the tree of a Graphic and return all the objects you’re looking for.

  • .allAnchors() returns an array of all the Anchor objects.
  • .allPaths() returns an array of all the Path objects.
  • .allCompoundPaths() returns an array of all the CompoundPath objects.
  • .allPathsAndCompoundPaths() returns an array of all CompoundPaths and all top-level Paths (meaning the Path is not contained within a CompoundPath). This is all the objects that can be styled.

Transforming Graphics

All of the Graphics have a .transform(...) method which is analogous to the Transform modifier in Cuttle.

To perform the above transform you could write:

input.transform({ position: Vec(3, 0), rotation: 30, });

That is, the transform method takes an object with the following properties, all optional:

  • position: a Vec
  • rotation: anumber in degrees
  • scale: a Vec for non-uniform scale or number for uniform scale
  • skew: a number in degrees
  • origin: a Vec for where the center of rotation and scale should be
  • Groups, Paths, and CompoundPaths do not have transformations.

    Note that unlike some other graphics frameworks that have a “scene graph” — a hierarchy of shapes — parent shapes in Cuttle do not have transformations. When you call .transform(...) on a parent shape, it will mutate the positions and handles of the Anchors (the leaf nodes of the tree).

Mutating methods and .clone()

You can make a copy of any Graphic object with the .clone() method. This will return a deep copy of the object. “Deep” means that children will also be copied recursively — for example if you .clone() a Path then all the child Anchors will also be cloned.

Note that most of the methods (e.g. .transform(...)) that you can call on a Graphic will mutate the object or its children. So if you don’t want to mutate your Graphic, you’ll want to first copy it with .clone().

For example, here is a simple modifier that returns the original input along with a copy of the input moved one unit to the right.

return [input, input.clone().transform({ position: Vec(1, 0) })];

The return value

All modifiers and code components need to return a Graphic. As a convenience, you can also return an array of Graphics which Cuttle will turn into a Group.