Skip to content
GitHub repository
Getting started

Introduction

pixi-silk is a Graphics-like object for PixiJS v8. It draws shapes as exact signed distance fields, so edges stay smooth and anti-aliased at any zoom and DPR.

Updated pixi-silk 0.1.0

pixi-silk adds SilkGraphics, a PixiJS v8 display object with an API close to Pixi’s Graphics. It does not turn shapes into triangles. The GPU evaluates each shape’s exact distance function at every pixel and derives coverage from it. The anti-aliasing is exact at every scale, without MSAA or extra render passes.

Source src/demos/versus.demo.ts
import { Container, Graphics, Text } from 'pixi.js';
import { SilkGraphics } from 'pixi-silk';
import { defineDemo } from './runtime';

// Left: Pixi v8 Graphics (tessellated, no MSAA). Right: SilkGraphics (distance fields).
export default defineDemo({
    size: [480, 240],
    controls: {
        zoom: { type: 'range', label: 'zoom', min: 1, max: 6, step: 0.01, value: 1 },
        spin: { type: 'toggle', label: 'rotate', value: true },
    },
    setup({ stage, params, tick }) {
        const sides = [new Container(), new Container()];
        const pixi = new Graphics();
        const silk = new SilkGraphics();

        sides[0].addChild(pixi);
        sides[1].addChild(silk);
        sides.forEach((side, i) => {
            const mask = new Graphics().rect(i * 240, 0, 240, 240).fill(0xffffff);
            const label = new Text({
                text: i ? 'SilkGraphics' : 'Graphics',
                style: { fill: 0x8e8e93, fontSize: 12, fontFamily: 'system-ui' },
            });

            label.position.set(i * 240 + 12, 10);
            side.mask = mask;
            stage.addChild(side, mask, label);
        });
        let angle = 0;

        tick((_t, dt) => {
            if (params.spin) angle += dt * 0.15;
            for (const [i, side] of sides.entries()) {
                side.pivot.set(120, 130);
                side.position.set(i * 240 + 120, 130);
                side.scale.set(params.zoom);
                side.rotation = angle;
            }
            for (const g of [pixi, silk]) {
                g.clear();
                g.circle(120, 130, 62).stroke({ width: 3, color: 0x64d2ff });
                g.roundRect(70, 90, 100, 80, 24).stroke({ width: 1, color: 0xffffff });
                g.circle(120, 130, 18).fill(0xff375f);
                for (let k = 0; k < 6; k++)
                    g.moveTo(40, 60 + k * 3)
                        .lineTo(200, 64 + k * 5)
                        .stroke({ width: 0.6, color: 0xffd60a });
            }
        });
    },
});
Pixi v8 Graphics on the left, SilkGraphics on the right. Zoom in and watch the edges.

Why v8 graphics stopped looking smooth#

PixiJS v8 builds Graphics geometry once, as triangles, when you draw. That is fast, but it has limits:

  • Curves are tessellated. Scale a circle up and its facets show. A thin line crawls between pixel rows as it moves.
  • Anti-aliasing is MSAA or nothing. antialias: true gives four samples per pixel on the main canvas. Filters and render textures stay aliased unless you opt each one into MSAA.
  • Filters render at resolution 1, so anything behind a filter is blurry on retina screens.
  • Gradients are 8-bit, so wide, dark gradients show bands.

What Silk does instead#

Pixi GraphicsSilkGraphics
Edgestessellated triangles, optional MSAAexact distance per pixel, 1-device-pixel filter
Zoomfacets appearexact at any scale
Thin linesbreak up below 1 pxkeep 1 px and fade (energy conserving)
Inside filters and render texturesaliased unless each target opts into MSAAsame quality everywhere
GradientssRGB, 8-bitOKLab, half-float ramps, dithered
Draw callsbatched geometryone instanced draw call per object

Key facts#

  • One SilkGraphics is one draw call, whatever it contains. Each primitive is one quad instance. Rebuilding 50,000 primitives every frame costs about 12 ms of CPU.
  • Shapes: rects and squircles (per-corner radii, continuous curvature), circles, ellipses, arcs, sectors, lines, polylines (smoothed, tapered), paths, areas between two series, hearts, stars, regular polygons and rounded triangles.
  • Paint: solid colours, gradients (linear, radial, conic and along-the-path), analytic gaussian blur for glows and soft shadows, and shader-side dashes.
  • createSilkApp creates a Pixi Application whose canvas maps 1:1 to device pixels, even at fractional ratios like 1.5 or 2.625. It follows DPR changes.
  • pixi-silk is written in TypeScript, renders with WebGL2 and is MIT licensed. pixi.js ^8 is a peer dependency.

Where to next#

API reference: SilkGraphics, createSilkApp