# Getting started

> Install pixi-silk next to pixi.js v8, create an app with createSilkApp and draw a squircle card, a gradient gauge and an area chart with SilkGraphics.

Source: https://pixi-silk.schmooky.dev/docs/getting-started/

pixi-silk adds `SilkGraphics`, a PixiJS v8 display object with an API close to `Graphics`. You
add it to the stage like any other container.

Demo sources run in the docs demo runner, `defineDemo({ setup({ stage, params, tick }) })`. In your own app, `stage` is `app.stage` (or a container on it), `params` holds the values of the demo controls, and `tick(fn)` is `app.ticker.add`, with `t` and `dt` in seconds.

Live demo `quick-start` (source):

```ts
import { Text } from 'pixi.js';
import { conic, SilkGraphics, vertical } from 'pixi-silk';
import { defineDemo, FONT, INK, label, PALETTE } from './runtime';

const GAUGE = conic([PALETTE.green, PALETTE.yellow, PALETTE.pink]);
const FILL = vertical(
    [
        [0, PALETTE.accent, 0.55],
        [1, PALETTE.accent, 0],
    ],
    { easing: 'smooth' },
);

// A small dashboard card: a squircle, a gauge with a gradient along its arc and an area chart.
export default defineDemo({
    title: 'Quick start card',
    size: [720, 220],
    // phones: the gauge above the chart, so the text keeps its size
    phone: { size: [360, 330] },
    controls: {
        progress: { type: 'range', label: 'progress', min: 0, max: 1, step: 0.01, value: 0.72 },
    },
    setup({ stage, params, tick, phone }) {
        // card, gauge centre, title and chart: one row on wide frames, two on phones
        const card = phone ? [16, 16, 328, 298] : [24, 24, 672, 172];
        const gauge = phone ? [96, 100] : [112, 110];
        const title = phone ? [184, 70] : [224, 42];
        const chart = phone ? { x: 40, step: 35, y: 250, base: 290 } : { x: 224, step: 56, y: 128, base: 172 };

        const g = new SilkGraphics();
        const percent = new Text({
            text: '',
            style: { fontFamily: FONT, fontSize: 22, fontWeight: '700', fill: INK.text },
        });
        const visits = new Text({
            text: '8,420',
            style: { fontFamily: FONT, fontSize: 22, fontWeight: '700', fill: INK.text },
        });

        percent.anchor.set(0.5);
        percent.position.set(gauge[0], gauge[1]);
        visits.position.set(title[0], title[1] + 18);
        stage.addChild(g, percent, label('Weekly visits', title[0], title[1]), visits);
        tick((t) => {
            // nine points across the chart area, swinging 18 px around its middle
            const wave: number[] = [];

            for (let i = 0; i < 9; i++) {
                wave.push(chart.x + i * chart.step, chart.y - Math.sin(i * 0.9 + t * 0.8) * 18 - i * 2.5);
            }
            g.clear();
            g.roundRect(card[0], card[1], card[2], card[3], 28, 0.6).fill(INK.surface); // squircle card
            g.arcSweep(gauge[0], gauge[1], 52, -Math.PI / 2, Math.PI * 2).stroke({ width: 14, color: INK.raised });
            g.arcSweep(gauge[0], gauge[1], 52, -Math.PI / 2, Math.PI * 2 * params.progress).stroke({
                width: 14,
                cap: 'round',
                gradient: GAUGE,
            }); // the gradient follows the arc
            g.area(wave, chart.base, { smooth: 'monotone' })
                .fill(FILL) // chart fill down to the base ...
                .stroke({ width: 2.5, color: PALETTE.accent, cap: 'round' }); // ... and its top line
            percent.text = `${Math.round(params.progress * 100)}%`;
        });
    },
});
```

## Install

```bash
npm install pixi-silk pixi.js
```

`pixi.js` 8.6 or newer is a peer dependency, so your app owns the renderer. The package is ESM
with TypeScript declarations and has no side effects, so a bundler keeps only what you import.

## Create the app

```ts

const { app } = await createSilkApp({
    parent: document.getElementById('stage')!, // the canvas fills this element
    background: 0x000000,
});
```

`createSilkApp` wraps `new Application()` and `app.init()`. It turns MSAA off, sizes the canvas
so one canvas pixel is one device pixel, and follows changes of the device pixel ratio. You can
keep your own `Application` instead. [Resolution](/docs/resolution/) lists the settings that matter.

## Draw

Shape methods add to the active path. `fill()` and `stroke()` paint it, and every call chains.

```ts

const GAUGE = conic([0x30d158, 0xffd60a, 0xff453a]); // spans the arc it is drawn on
const g = new SilkGraphics();

g.roundRect(10, 10, 340, 140, 22, 0.6).fill(0x1c1c1e); // radius 22, squircle smoothing 0.6
g.arcSweep(80, 80, 44, -Math.PI / 2, Math.PI * 1.5).stroke({ width: 12, cap: 'round', gradient: GAUGE });
g.area([120, 100, 170, 80, 220, 92, 270, 60, 320, 70], 130, { smooth: 'monotone' })
    .fill(vertical([[0, 0xff9f0a, 0.8], [1, 0xff9f0a, 0]]))
    .stroke({ width: 2, color: 0xff9f0a, cap: 'round' }); // a stroke right after a fill draws the top line

app.stage.addChild(g);
```

The card is a squircle, the gauge is one arc with a conic gradient along it, and the chart is a
smoothed area with a fading fill.

## Animate

Redraw every frame. `clear()` keeps the GPU buffers, so a rebuild only rewrites numbers.

```ts
app.ticker.add((ticker) => {
    const t = ticker.lastTime / 1000;

    g.clear();
    g.arcSweep(80, 80, 44, -Math.PI / 2, Math.PI * 2 * (0.5 + 0.4 * Math.sin(t)))
        .stroke({ width: 12, cap: 'round', gradient: GAUGE });
});
```

Create gradients once and reuse them. Ramps with the same stops share one row of the gradient
atlas, and a reused object skips parsing the stops again.

## What it does differently

`Graphics` turns shapes into triangles when you draw, and only MSAA smooths their edges.
`SilkGraphics` draws each shape as a quad. The fragment shader evaluates the shape's exact
distance function at every pixel and turns the distance into coverage.

Two things follow from that. Edges stay sharp at any zoom and in filters and render textures,
because nothing was tessellated. And one `SilkGraphics` renders in one instanced draw call,
whatever it holds. Call `enableSilkBatching()` before you create objects to draw runs of them in
one call too. [Anti-aliasing compared](/docs/anti-aliasing-compared/) sets this against MSAA,
`@pixi/graphics-smooth` and supersampling, and [How it works](/docs/how-it-works/) walks
through the shader.

It renders with WebGL2 by default. [Renderers](/docs/renderers/) shows how to turn on WebGPU.

## Where it stops

| You want | Use |
|---|---|
| Texture or pattern fills | a Pixi `Sprite` or `TilingSprite` |
| A whole SVG file | Pixi's `Graphics.svg()`. `svgPath(d)` takes one path's `d` attribute |
| Text | `SilkText` from `pixi-silk/text`, a separate entry point |

## Where next

- [Choose an entry point](/docs/choose-an-entry-point/) lists what each import holds.
- [Migrating from Graphics](/docs/migrating-from-graphics/) maps your existing calls.
- [Your first widget](/docs/first-widget/) builds a button with a glow, hover and press.
- [Shapes](/docs/shapes/) lists every primitive.
