Skip to content
pixi-silk
GitHub repository
Shapes & strokes

Shapes

Rects and squircles with per-corner radii, circles, ellipses, polygons, stars, arcs, rings and sectors, plus the transform stack that rotates them.

Updated pixi-silk 1.0.1View as Markdown

A shape method adds a primitive to the active path, and fill() or stroke() paints it. Pixi’s Graphics works the same way, so g.rect(...).circle(...).fill(0x0a84ff) fills both shapes.

Turn on outline or rotate.
g.roundRect(0, 0, 200, 80, 20, 0.6).fill(0x1c1c1e).stroke({ width: 2, color: 0x3a3a3c });

That draws a card with squircle corners and a border. A stroke() right after fill() lands in the same primitive, so the two paints meet without a seam. Stroke options are on Strokes & dashes.

Rectangles, squircles and pills#

Drag smoothing. Pink is a circular corner of the same radius.
g.rect(x, y, width, height);
g.roundRect(x, y, width, height, radius);              // circular corners
g.roundRect(x, y, width, height, radius, 0.6);         // squircle corners
g.roundRect(x, y, width, height, [24, 24, 8, 8]);      // per corner: tl, tr, br, bl
g.pill(x, y, width, height);                            // fully round ends

The sixth argument, smoothing, runs from 0 to 1. Above 0 the corner becomes a superellipse arc whose curvature grows gradually, the corner of iOS app icons. iOS uses about 0.6. A smoothed corner is as deep as a circular one of the same radius at its midpoint, so switching keeps the layout.

Circles, ellipses and hearts#

g.circle(cx, cy, radius);
g.ellipse(cx, cy, radiusX, radiusY);
g.heart(cx, cy, width, rounding);      // rounding 0 to 0.3 puffs it up

Polygons, stars and triangles#

g.regularPoly(cx, cy, radius, sides, rotation, cornerRadius);   // first vertex points up
g.star(cx, cy, points, radius, innerRadius, rotation, cornerRadius);
g.triangle(x0, y0, x1, y1, x2, y2, cornerRadius);

cornerRadius rounds every corner with a true circular arc. Leave it at 0 for sharp corners, which then take the stroke’s join. For free outlines, use poly(), moveTo() or svgPath() on Lines & paths.

Arcs and rings#

Drag progress past 1 and switch the cap.
g.arcSweep(100, 100, 60, -Math.PI / 2, Math.PI * 2 * progress)
    .stroke({ width: 14, cap: 'round', color: 0x30d158 });

arcSweep(cx, cy, radius, startAngle, sweep) takes a signed sweep that turns clockwise on screen. arc(cx, cy, radius, startAngle, endAngle, anticlockwise) has the Canvas signature. Angles are in radians with y pointing down, so -Math.PI / 2 is 12 o’clock. A sweep of a full turn or more draws a closed ring.

Arcs are open curves, so you stroke them. cap defaults to 'butt', as in Pixi. Each arc starts a subpath of its own. Unlike Graphics.arc, it does not draw a line from the previous point.

A conic() gradient on an arc spans that arc. Its start and sweep default to the arc’s own, so the ramp runs from cap to cap however long the arc is.

const RING = conic([0xfa114f, 0xff5e8a]);

g.arcSweep(100, 100, 60, -Math.PI / 2, sweep).stroke({ width: 16, cap: 'round', gradient: RING });

Sectors and donut segments#

const slices = [0.4, 0.25, 0.2, 0.15];
const COLORS = [0x0a84ff, 0x30d158, 0xffd60a, 0xff375f];
let a = -Math.PI / 2;

for (const [i, share] of slices.entries()) {
    const sweep = share * Math.PI * 2;

    g.sector(120, 120, 90, a + 0.02, a + sweep - 0.02, 50, 6).fill(COLORS[i]);
    a += sweep;
}

sector(cx, cy, radius, startAngle, endAngle, innerRadius, cornerRadius) is a closed shape. An innerRadius above 0 turns the pie slice into a donut segment, and cornerRadius rounds its four corners. The loop above draws a donut chart with small gaps between the slices.

One shape from several#

Add union: true to paint every shape of the path as one. Overlaps are painted once, so a translucent arrow made of a shaft and a head shows no darker joint.

g.rect(0, -2, 40, 4)
    .triangle(36, -8, 50, 0, 36, 8)
    .fill({ color: 0x0a84ff, alpha: 0.6, union: true });

Let the shapes overlap a little. A stroke() right after a union fill follows the outline of the union. To cut, intersect or nest shapes, see Shape operations.

Rotate and scale with the transform stack#

Change the speed.
g.save()
    .translateTransform(210, 110)
    .rotateTransform(Math.PI / 4)
    .scaleTransform(1.5);
g.roundRect(-20, -10, 40, 20, 8).fill(0xff9f0a);
g.restore();

The rect is drawn in the transformed space: moved to (210, 110), turned 45 degrees and scaled by 1.5. SilkGraphics has the transform stack of Pixi’s GraphicsContext.

MethodWhat it does
save(), restore()Push and pop the current transform
translateTransform(x, y = x)Move
rotateTransform(angle)Rotate, in radians
scaleTransform(x, y = x)Scale
setTransform(a, b, c, d, tx, ty)Replace the transform with a matrix
resetTransform()Go back to the identity

Shapes are stored already transformed, and rotated rects, ellipses and polygons keep their exact outline. Stroke widths, dash lengths and blur radii scale with the uniform part of the scale.

The transform stack suits icons and repeated parts that you redraw. For an object that moves as a whole, such as a card sliding in, give it its own SilkGraphics and animate its position, rotation or scale. That changes one matrix and rebuilds nothing.

API reference: SilkGraphics, conic

Go deeper

Experiments on this page

Full-screen scenes. Each one also opens in Studio with its source.