Shapes

The graphical elements are divided in 4 categories:

Shape Rendering Model

Grouping and Ordering Rules

More formally:

Notes

  1. Certain modifier operations (e.g. sequential Trim) may require information about shapes from different groups, thus Render() calls cannot always be issued based on single-pass local knowledge.

  2. Transforms can affect both shapes and styles (e.g. stroke width). For a given (shape,style), the shape and style transforms are not necessarily equal.

  3. Shapes without an applicable style are not rendered.

  4. This rendering model is based on AfterEffects' Shape Layer semantics.

Rendering Convention

Shapes defined in this section contain rendering instructions. These instructions are used to generate the path as a bezier curve.

Implementations MAY use different algorithms or primitives to render the shapes but the result MUST be equivalent to the paths defined here.

Some instructions define named values for clarity and illustrative purposes, implementations are not required to have them explicitly defined in their rendering process.

When referencing animated properties, the rendering instruction will use the same name as in the JSON but it's assumed they refer to their value at a given point in time rather than the property itself. For Vector values, value.x and value.y in the instructions are equivalent to value[0] and value[1] respectively.

All paths MUST be closed unless specified otherwise in the rendering instructions.

When instructions call for an equality comparison between two values, implementations MAY consider similar values to be equal to overcome numerical instability.

Bezier Conversions

This documents includes algorithms to convert parametric shapes into bezier curves.

Implementations MAY use different implementations than the algorithms provided here but the output shape MUST be visually indistinguishable from the output of these algorithms.

Furthermore, when drawing individual shapes the stroke order and direction is not importand but implementations of Trim Path MUST follow the stroke order as defined by these algorithms.

Drawing instructions will contain the following commands:

Approximating Ellipses with Cubic Bezier

An elliptical quadrant can be approximated by a cubic bezier segment with tangents of length $radius * E_t.

Where

Et0.5519150244935105707435627

See this article for the math behind it.

When implementations render elliptical arcs using bezier curves, they SHOULD use this constant, a similar approximation, or elliptical arc drawing primitives.

Graphic Element

Element used to display vector data in a shape layer

Composition Diagram for Graphic Element Graphic Element Visual Object Shape Style Gradient Fill Gradient Stroke Stroke Shape PolyStar Rectangle Ellipse Path Group Modifier Trim Path Transform Shape
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string

Shape Type

Shape Type

The ty property defines the specific element type based on the following values:

ty Type
'el' Ellipse
'fl' Fill
'gf' Gradient
'gs' Gradient Stroke
'gr' Group
'sh' Path
'sr' PolyStar
'rc' Rectangle
'st' Stroke
'tr' Transform Shape
'tm' Trim Path

Hidden shapes (hd: True) are ignored, and do not contribute to rendering nor modifier operations.

Shapes

Drawable shape, defines the actual shape but not the style

Composition Diagram for Shape Shape Graphic Element Visual Object PolyStar Rectangle Ellipse Path
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string

Shape Type

Shape Type

d Shape Direction

Direction

Direction the shape is drawn as, mostly relevant when using trim path

Ellipse

Ellipse shape

Composition Diagram for Ellipse Ellipse Shape Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'el'

Shape Type

Shape Type

d Shape Direction

Direction

Direction the shape is drawn as, mostly relevant when using trim path

p Position

Position

Position

s Vector

Size

Size


Ellipse
    Inputs:
        p2
        s2
    
    An ellipse is drawn from the top quadrant point going clockwise:
    radiuss2
    tangentradius·Et
    xp.x
    yp.y

    Set shape closed
    Add vertex (x,yradius.y)
    Set in tangent (tangent.x,0)
    Set out tangent (tangent.x,0)
    Add vertex (x+radius.x,y)
    Set in tangent (0,tangent.y)
    Set out tangent (0,tangent.y)
    Add vertex (x,y+radius.y)
    Set in tangent (tangent.x,0)
    Set out tangent (tangent.x,0)
    Add vertex (xradius.x,y)
    Set in tangent (0,tangent.y)
    Set out tangent (0,tangent.y)

def ellipse(shape: Bezier, p: Vector2D, s: Vector2D):
    # An ellipse is drawn from the top quadrant point going clockwise:
    radius = s / 2
    tangent = radius * ELLIPSE_CONSTANT
    x = p.x
    y = p.y

    shape.closed = True
    shape.add_vertex(Vector2D(x, y - radius.y))
    shape.set_in_tangent(Vector2D(-tangent.x, 0))
    shape.set_out_tangent(Vector2D(tangent.x, 0))
    shape.add_vertex(Vector2D(x + radius.x, y))
    shape.set_in_tangent(Vector2D(0, -tangent.y))
    shape.set_out_tangent(Vector2D(0, tangent.y))
    shape.add_vertex(Vector2D(x, y + radius.y))
    shape.set_in_tangent(Vector2D(tangent.x, 0))
    shape.set_out_tangent(Vector2D(-tangent.x, 0))
    shape.add_vertex(Vector2D(x - radius.x, y))
    shape.set_in_tangent(Vector2D(0, tangent.y))
    shape.set_out_tangent(Vector2D(0, -tangent.y))

void ellipse(Bezier shape, Vector2D p, Vector2D s)
{
    // An ellipse is drawn from the top quadrant point going clockwise:
    radius = s / 2;
    tangent = radius * ELLIPSE_CONSTANT;
    x = p.x;
    y = p.y;

    shape.closed = true;
    shape.add_vertex(Vector2D(x, y - radius.y));
    shape.set_in_tangent(Vector2D(-tangent.x, 0));
    shape.set_out_tangent(Vector2D(tangent.x, 0));
    shape.add_vertex(Vector2D(x + radius.x, y));
    shape.set_in_tangent(Vector2D(0, -tangent.y));
    shape.set_out_tangent(Vector2D(0, tangent.y));
    shape.add_vertex(Vector2D(x, y + radius.y));
    shape.set_in_tangent(Vector2D(tangent.x, 0));
    shape.set_out_tangent(Vector2D(-tangent.x, 0));
    shape.add_vertex(Vector2D(x - radius.x, y));
    shape.set_in_tangent(Vector2D(0, tangent.y));
    shape.set_out_tangent(Vector2D(0, -tangent.y));
}

function ellipse(shape: Bezier, p: Vector2D, s: Vector2D) {
    // An ellipse is drawn from the top quadrant point going clockwise:
    radius = String / 2;
    tangent = radius * ELLIPSE_CONSTANT;
    x = p.x;
    y = p.y;

    shape.closed = true;
    shape.addVertex(new Vector2D(x, y - radius.y));
    shape.setInTangent(new Vector2D(-tangent.x, 0));
    shape.setOutTangent(new Vector2D(tangent.x, 0));
    shape.addVertex(new Vector2D(x + radius.x, y));
    shape.setInTangent(new Vector2D(0, -tangent.y));
    shape.setOutTangent(new Vector2D(0, tangent.y));
    shape.addVertex(new Vector2D(x, y + radius.y));
    shape.setInTangent(new Vector2D(tangent.x, 0));
    shape.setOutTangent(new Vector2D(-tangent.x, 0));
    shape.addVertex(new Vector2D(x - radius.x, y));
    shape.setInTangent(new Vector2D(0, tangent.y));
    shape.setOutTangent(new Vector2D(0, -tangent.y));
}

Implementations MAY use elliptical arcs to render an ellipse.

Ellipse rendering guide

Rectangle

A simple rectangle shape

Composition Diagram for Rectangle Rectangle Shape Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'rc'

Shape Type

Shape Type

d Shape Direction

Direction

Direction the shape is drawn as, mostly relevant when using trim path

p Position

Position

Center of the rectangle

s Vector

Size

Size

r Scalar

Roundness

Rounded corners radius

Rendering algorithm:


Rectangle
    Inputs:
        p2
        s2
        r
    
    leftp.xs.x2
    rightp.x+s.x2
    topp.ys.y2
    bottomp.y+s.y2

    Set shape closed

    If r0

        The rectangle is rendered from the top-right going clockwise

        Add vertex (right,top)
        Add vertex (right,bottom)
        Add vertex (left,bottom)
        Add vertex (left,top)

    Otherwise

        Rounded corners must be taken into account

        roundedmin(s.x2,s.y2,r)
        tangentrounded·Et

        Add vertex (right,top+rounded)
        Set in tangent (0,tangent)
        Add vertex (right,bottomrounded)
        Set out tangent (0,tangent)
        Add vertex (rightrounded,bottom)
        Set in tangent (tangent,0)
        Add vertex (left+rounded,bottom)
        Set out tangent (tangent,0)
        Add vertex (left,bottomrounded)
        Set in tangent (0,tangent)
        Add vertex (left,top+rounded)
        Set out tangent (0,tangent)
        Add vertex (left+rounded,top)
        Set in tangent (tangent,0)
        Add vertex (rightrounded,top)
        Set out tangent (tangent,0)

def rectangle(shape: Bezier, p: Vector2D, s: Vector2D, r: float):
    left: float = p.x - s.x / 2
    right: float = p.x + s.x / 2
    top: float = p.y - s.y / 2
    bottom: float = p.y + s.y / 2

    shape.closed = True

    if r <= 0:

        # The rectangle is rendered from the top-right going clockwise

        shape.add_vertex(Vector2D(right, top))
        shape.add_vertex(Vector2D(right, bottom))
        shape.add_vertex(Vector2D(left, bottom))
        shape.add_vertex(Vector2D(left, top))

    else:

        # Rounded corners must be taken into account

        rounded: float = min(s.x/2, s.y/2, r)
        tangent: float = rounded * ELLIPSE_CONSTANT

        shape.add_vertex(Vector2D(right, top + rounded))
        shape.set_in_tangent(Vector2D(0, -tangent))
        shape.add_vertex(Vector2D(right, bottom - rounded))
        shape.set_out_tangent(Vector2D(0, tangent))
        shape.add_vertex(Vector2D(right - rounded, bottom))
        shape.set_in_tangent(Vector2D(tangent, 0))
        shape.add_vertex(Vector2D(left + rounded, bottom))
        shape.set_out_tangent(Vector2D(-tangent, 0))
        shape.add_vertex(Vector2D(left, bottom - rounded))
        shape.set_in_tangent(Vector2D(0, tangent))
        shape.add_vertex(Vector2D(left, top + rounded))
        shape.set_out_tangent(Vector2D(0, -tangent))
        shape.add_vertex(Vector2D(left + rounded, top))
        shape.set_in_tangent(Vector2D(-tangent, 0))
        shape.add_vertex(Vector2D(right - rounded, top))
        shape.set_out_tangent(Vector2D(tangent, 0))

void rectangle(Bezier shape, Vector2D p, Vector2D s, float r)
{
    float left = p.x - s.x / 2;
    float right = p.x + s.x / 2;
    float top = p.y - s.y / 2;
    float bottom = p.y + s.y / 2;

    shape.closed = true;

    if ( r <= 0 )
    {
        // The rectangle is rendered from the top-right going clockwise

        shape.add_vertex(Vector2D(right, top));
        shape.add_vertex(Vector2D(right, bottom));
        shape.add_vertex(Vector2D(left, bottom));
        shape.add_vertex(Vector2D(left, top));
    }
    // Rounded corners must be taken into account

    else
    {
        float rounded = std::min(s.x / 2, s.y / 2, r);
        float tangent = rounded * ELLIPSE_CONSTANT;

        shape.add_vertex(Vector2D(right, top + rounded));
        shape.set_in_tangent(Vector2D(0, -tangent));
        shape.add_vertex(Vector2D(right, bottom - rounded));
        shape.set_out_tangent(Vector2D(0, tangent));
        shape.add_vertex(Vector2D(right - rounded, bottom));
        shape.set_in_tangent(Vector2D(tangent, 0));
        shape.add_vertex(Vector2D(left + rounded, bottom));
        shape.set_out_tangent(Vector2D(-tangent, 0));
        shape.add_vertex(Vector2D(left, bottom - rounded));
        shape.set_in_tangent(Vector2D(0, tangent));
        shape.add_vertex(Vector2D(left, top + rounded));
        shape.set_out_tangent(Vector2D(0, -tangent));
        shape.add_vertex(Vector2D(left + rounded, top));
        shape.set_in_tangent(Vector2D(-tangent, 0));
        shape.add_vertex(Vector2D(right - rounded, top));
        shape.set_out_tangent(Vector2D(tangent, 0));
    }
}

function rectangle(shape: Bezier, p: Vector2D, s: Vector2D, r: number) {
    let left: number = p.x - String.x / 2;
    let right: number = p.x + String.x / 2;
    let top: number = p.y - String.y / 2;
    let bottom: number = p.y + String.y / 2;

    shape.closed = true;

    if ( String <= 0 ) {

        // The rectangle is rendered from the top-right going clockwise

        shape.addVertex(new Vector2D(right, top));
        shape.addVertex(new Vector2D(right, bottom));
        shape.addVertex(new Vector2D(left, bottom));
        shape.addVertex(new Vector2D(left, top));

    } else {

        // Rounded corners must be taken into account

        let rounded: number = Math.min(String.x / 2, String.y / 2, String);
        let tangent: number = rounded * ELLIPSE_CONSTANT;

        shape.addVertex(new Vector2D(right, top + rounded));
        shape.setInTangent(new Vector2D(0, -tangent));
        shape.addVertex(new Vector2D(right, bottom - rounded));
        shape.setOutTangent(new Vector2D(0, tangent));
        shape.addVertex(new Vector2D(right - rounded, bottom));
        shape.setInTangent(new Vector2D(tangent, 0));
        shape.addVertex(new Vector2D(left + rounded, bottom));
        shape.setOutTangent(new Vector2D(-tangent, 0));
        shape.addVertex(new Vector2D(left, bottom - rounded));
        shape.setInTangent(new Vector2D(0, tangent));
        shape.addVertex(new Vector2D(left, top + rounded));
        shape.setOutTangent(new Vector2D(0, -tangent));
        shape.addVertex(new Vector2D(left + rounded, top));
        shape.setInTangent(new Vector2D(-tangent, 0));
        shape.addVertex(new Vector2D(right - rounded, top));
        shape.setOutTangent(new Vector2D(tangent, 0));
    }
}

Rectangle rendering guide

Path

Custom Bezier shape

Composition Diagram for Path Path Shape Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'sh'

Shape Type

Shape Type

d Shape Direction

Direction

Direction the shape is drawn as, mostly relevant when using trim path

ks Bezier

Shape

Bezier path

PolyStar

Star or regular polygon

Composition Diagram for PolyStar PolyStar Shape Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'sr'

Shape Type

Shape Type

d Shape Direction

Direction

Direction the shape is drawn as, mostly relevant when using trim path

p Position

Position

Position

or Scalar

Outer Radius

Outer Radius

os Scalar

Outer Roundness

Outer Roundness as a percentage

r Scalar

Rotation

Rotation, clockwise in degrees

pt Scalar

Points

Points

sy Star Type

Star Type

Star Type

ir Scalar

Inner Radius

Inner Radius

is Scalar

Inner Roundness

Inner Roundness as a percentage


Polystar
    Inputs:
        p2
        pt
        r
        or
        os
        sy
        ir
        is
    
    pointspt
    αr·π180π2
    θπpoints
    tanLenout2·π·or4·points·os100
    tanLenin2·π·ir4·points·is100

    Set shape closed

    For each i in [0,points)
        βα+i·θ·2
        vout(or·cos(β),or·sin(β))
        Add vertex p+vout

        If os0or0
            We need to add bezier tangents
            tanoutvout·tanLenoutor
            Set in tangent (tanout.y,tanout.x)
            Set out tangent (tanout.y,tanout.x)

        If sy=1
            We need to add a vertex towards the inner radius to make a star
            vin(ir·cos(β+θ),ir·sin(β+θ))
            Add vertex p+vin

            If is0ir0
                We need to add bezier tangents
                taninvin·tanLeninir
                Set in tangent (tanin.y,tanin.x)
                Set out tangent (tanin.y,tanin.x)

def polystar(shape: Bezier, p: Vector2D, pt: float, r: float, or_: float, os: float, sy: int, ir: float, is_: float):
    points: int = int(round(pt))
    alpha: float = -r * math.pi / 180 - math.pi / 2
    theta: float = -math.pi / points
    tan_len_out: float = (2 * math.pi * or_) / (4 * points) * (os / 100)
    tan_len_in: float = (2 * math.pi * ir) / (4 * points) * (is_ / 100)

    shape.closed = True

    for i in range(points):
        beta: float = alpha + i * theta * 2
        v_out: Vector2D = Vector2D(or_ * math.cos(beta),  or_ * math.sin(beta))
        shape.add_vertex(p + v_out)

        if os != 0 and or_ != 0:
            # We need to add bezier tangents
            tan_out: Vector2D = v_out * tan_len_out / or_
            shape.set_in_tangent(Vector2D(-tan_out.y, tan_out.x))
            shape.set_out_tangent(Vector2D(tan_out.y, -tan_out.x))

        if sy == 1:
            # We need to add a vertex towards the inner radius to make a star
            v_in: Vector2D = Vector2D(ir * math.cos(beta + theta), ir * math.sin(beta + theta))
            shape.add_vertex(p + v_in)

            if is_ != 0 and ir != 0:
                # We need to add bezier tangents
                tan_in = v_in * tan_len_in / ir
                shape.set_in_tangent(Vector2D(-tan_in.y, tan_in.x))
                shape.set_out_tangent(Vector2D(tan_in.y, -tan_in.x))

void polystar(Bezier shape, Vector2D p, float pt, float r, float or_, float os, int sy, float ir, float is)
{
    int points = std::round(pt);
    float alpha = -r * std::numbers::pi / 180 - std::numbers::pi / 2;
    float theta = -std::numbers::pi / points;
    float tan_len_out = 2 * std::numbers::pi * or_ / 4 * points * os / 100;
    float tan_len_in = 2 * std::numbers::pi * ir / 4 * points * is / 100;

    shape.closed = true;

    for ( int i = 0; i < points; i++ )
    {
        float beta = alpha + i * theta * 2;
        Vector2D v_out(or_ * std::cos(beta), or_ * std::sin(beta));
        shape.add_vertex(p + v_out);

        if ( os != 0 && or_ != 0 )
        {
            // We need to add bezier tangents
            Vector2D tan_out = v_out * tan_len_out / or_;
            shape.set_in_tangent(Vector2D(-tan_out.y, tan_out.x));
            shape.set_out_tangent(Vector2D(tan_out.y, -tan_out.x));
        }

        if ( sy == 1 )
        {
            // We need to add a vertex towards the inner radius to make a star
            Vector2D v_in(ir * std::cos(beta + theta), ir * std::sin(beta + theta));
            shape.add_vertex(p + v_in);

            if ( is != 0 && ir != 0 )
            {
                // We need to add bezier tangents
                tan_in = v_in * tan_len_in / ir;
                shape.set_in_tangent(Vector2D(-tan_in.y, tan_in.x));
                shape.set_out_tangent(Vector2D(tan_in.y, -tan_in.x));
            }
        }
    }
}

function polystar(shape: Bezier, p: Vector2D, pt: number, r: number, or: number, os: number, sy: number, ir: number, is: number) {
    let points: number = new Number(round(pt));
    let alpha: number = -String * Math.PI / 180 - Math.PI / 2;
    let theta: number = -Math.PI / points;
    let tanLenOut: number = 2 * Math.PI * or / 4 * points * os / 100;
    let tanLenIn: number = 2 * Math.PI * ir / 4 * points * is / 100;

    shape.closed = true;

    for ( let i: number = 0; i < points; i++ ) {
        let beta: number = alpha + i * theta * 2;
        let vOut: Vector2D = new Vector2D(or * Math.cos(beta), or * Math.sin(beta));
        shape.addVertex(p + vOut);

        if ( os != 0 && or != 0 ) {
            // We need to add bezier tangents
            let tanOut: Vector2D = vOut * tanLenOut / or;
            shape.setInTangent(new Vector2D(-tanOut.y, tanOut.x));
            shape.setOutTangent(new Vector2D(tanOut.y, -tanOut.x));
        }

        if ( sy == 1 ) {
            // We need to add a vertex towards the inner radius to make a star
            let vIn: Vector2D = new Vector2D(ir * Math.cos(beta + theta), ir * Math.sin(beta + theta));
            shape.addVertex(p + vIn);

            if ( is != 0 && ir != 0 ) {
                // We need to add bezier tangents
                tanIn = vIn * tanLenIn / ir;
                shape.setInTangent(new Vector2D(-tanIn.y, tanIn.x));
                shape.setOutTangent(new Vector2D(tanIn.y, -tanIn.x));
            }
        }
    }
}

Grouping

Group

Shape Element that can contain other shapes

Composition Diagram for Group Group Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'gr'

Shape Type

Shape Type

np number

Number Of Properties

Number Of Properties

it array of Graphic Element

Shapes

Shapes

A group defines a render stack, elements within a group MUST be rendered in reverse order (the first object in the list will appear on top of elements further down).

  1. Apply the transform
  2. Render Styles and child groups in the transformed coordinate system.

Transform

Group transform

Composition Diagram for Transform Shape Transform Shape Graphic Element Transform Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'tr'

Shape Type

Shape Type

a Position

Anchor Point

Anchor point: a position (relative to its parent) around which transformations are applied (ie: center for rotation / scale)

p Splittable Position

Position

Position / Translation

r Scalar

Rotation

Rotation in degrees, clockwise

s Vector

Scale

Scale factor, [100, 100] for no scaling

o Scalar

Opacity

Opacity

sk Scalar

Skew

Skew amount as an angle in degrees

sa Scalar

Skew Axis

Direction along which skew is applied, in degrees (0 skews along the X axis, 90 along the Y axis)

Transform shapes MUST always be present in the group and they MUST be the last item in the it array.

They modify the group's coordinate system the same way as Layer Transform.

Style

Describes the visual appearance (like fill and stroke) of neighbouring shapes

Composition Diagram for Shape Style Shape Style Graphic Element Visual Object Gradient Fill Gradient Stroke Stroke
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string

Shape Type

Shape Type

o Scalar

Opacity

Opacity, 100 means fully opaque

Shapes styles MUST apply their style to the collected shapes that come before them in stacking order.

Fill

Solid fill color

Composition Diagram for Fill Fill Shape Style Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'fl'

Shape Type

Shape Type

o Scalar

Opacity

Opacity, 100 means fully opaque

c Color

Color

Color

r Fill Rule

Fill Rule

Fill Rule

Stroke

Solid stroke

Composition Diagram for Stroke Stroke Shape Style Base Stroke Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'st'

Shape Type

Shape Type

o Scalar

Opacity

Opacity, 100 means fully opaque

lc Line Cap

Line Cap

Line Cap

lj Line Join

Line Join

Line Join

ml number

Miter Limit

Miter Limit

ml2 Scalar

Miter Limit

Animatable alternative to ml

w Scalar

Width

Stroke width

d array of Stroke Dash

Dashes

Dashed line definition

c Color

Color

Stroke color

Stroke Dashes

An item used to described the dash pattern in a stroked path

A stroke dash array consists of n dash entries, [n-1,n] gap entries and [0-1] offset entries.

Dash and gap entries MUST all be in a continuous order and alternate between dash and gap, starting with dash. If there are an odd number of dashes + gaps, the sequence will repeat with dashes and gaps reversed. For example a sequence of [4d, 8g, 16d] MUST be rendered as [4d, 8g, 16d, 4g, 8d, 16g].

Offset entry, if present, MUST be at the end of the array.

Composition Diagram for Stroke Dash Stroke Dash Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

n Stroke Dash Type

Dash Type

Dash Type

v Scalar

Length

Length of the dash

Gradient Fill

Gradient fill color

Composition Diagram for Gradient Gradient Shape Style Base Gradient Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'gf'

Shape Type

Shape Type

o Scalar

Opacity

Opacity, 100 means fully opaque

g Gradient

Colors

Gradient colors

s Position

Start Point

Starting point for the gradient

e Position

End Point

End point for the gradient

t Gradient Type

Gradient Type

Type of the gradient

h Scalar

Highlight Length

Highlight Length, as a percentage between s and e

a Scalar

Highlight Angle

Highlight Angle in clockwise degrees, relative to the direction from s to e

r Fill Rule

Fill Rule

Fill Rule

Gradient Stroke

Gradient stroke

Composition Diagram for Gradient Stroke Gradient Stroke Shape Style Base Stroke Base Gradient Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'gs'

Shape Type

Shape Type

o Scalar

Opacity

Opacity, 100 means fully opaque

lc Line Cap

Line Cap

Line Cap

lj Line Join

Line Join

Line Join

ml number

Miter Limit

Miter Limit

ml2 Scalar

Miter Limit

Animatable alternative to ml

w Scalar

Width

Stroke width

d array of Stroke Dash

Dashes

Dashed line definition

g Gradient

Colors

Gradient colors

s Position

Start Point

Starting point for the gradient

e Position

End Point

End point for the gradient

t Gradient Type

Gradient Type

Type of the gradient

h Scalar

Highlight Length

Highlight Length, as a percentage between s and e

a Scalar

Highlight Angle

Highlight Angle in clockwise degrees, relative to the direction from s to e

Modifiers

Modifiers change the bezier curves of neighbouring shapes

Modifiers replace shapes in the render stack by applying operating on the bezier path of to the collected shapes that come before it in stacking order.

Trim Path

Trims shapes into a segment

Composition Diagram for Trim Path Trim Path Modifier Graphic Element Visual Object
Attribute Type Title Description
nm string

Name

Human readable name, as seen from editors and the like

hd boolean

Hidden

Whether the shape is hidden

ty string = 'tm'

Shape Type

Shape Type

s Scalar

Start

Segment start

e Scalar

End

Segment end

o Scalar

Offset

Offset

m Trim Multiple Shapes

Multiple

How to treat multiple copies

When rendering trim path, the order of bezier points MUST be the same as rendering instructions given for each shape in this section.

Rendering trim path can be rather complex.

Given

offset={o360o360o0o360o360o<0start=offset+min(1,max(0,min(s,e)100))end=offset+min(1,max(0,max(s,e)100))

If s and e are equal, implementations MUST NOT render any shapes.

If s=0 and e=1, the input shape MUST be rendered as-is.

To render trim path, implementations MUST consider the actual length of each shape (they MAY use approximations). Once the shapes are collected, the segment to render is given by the percentages start and end.

When trim path is applied to multiple shapes, the m property MUST be considered when applying the modifier: