# Performance

> One instanced draw call per SilkGraphics and about 12 ms of CPU to rebuild 50,000 primitives, plus tips for static layers, gradients and fill rate.

Source: https://pixi-silk.schmooky.dev/docs/performance/

Live demo `stress` (source):

```ts
import { Text } from 'pixi.js';
import { SilkGraphics } from 'pixi-silk';
import { defineDemo } from './runtime';

// Everything is rebuilt every frame: one SilkGraphics, one draw call, however many primitives.
export default defineDemo({
    size: [480, 260],
    controls: {
        count: { type: 'range', label: 'primitives', min: 500, max: 30000, step: 500, value: 5000 },
    },
    setup({ stage, params, tick }) {
        const g = new SilkGraphics();
        const stats = new Text({
            text: '',
            style: { fill: 0xffffff, fontSize: 12, fontFamily: 'ui-monospace, monospace' },
        });

        stats.position.set(12, 10);
        stage.addChild(g, stats);
        let cpu = 0;

        tick((t) => {
            const start = performance.now();

            g.clear();
            for (let i = 0; i < params.count; i++) {
                const a = i * 2.399963 + t * 0.2;
                const r = Math.sqrt(i / params.count) * 120;
                const x = 240 + Math.cos(a) * r * 1.8;
                const y = 130 + Math.sin(a) * r;

                if (i % 3 === 0) g.circle(x, y, 2.2).fill(0xff375f);
                else if (i % 3 === 1) g.roundRect(x - 2, y - 2, 4, 4, 1).fill(0x0a84ff);
                else g.line(x, y, x + 5, y + 2).stroke({ width: 1, color: 0x30d158 });
            }
            cpu = cpu * 0.9 + (performance.now() - start) * 0.1;
            stats.text = `${params.count} primitives, 1 draw call, rebuilt in ${cpu.toFixed(1)} ms`;
        });
    },
});
```

## The cost model

- Each `SilkGraphics` is one **draw call**, whatever it contains.
- The **CPU** writes 40 floats per primitive into a reusable buffer. Rebuilding 50,000 primitives
  every frame takes about 12 ms on a laptop. Typical UIs (hundreds of primitives) cost well under
  0.5 ms.
- The **GPU** shades each primitive as one quad sized to its bounds plus a one-pixel margin, once
  per covered pixel. Cost scales with covered area, like any 2D renderer. Large blurs grow the quad
  by 3σ.
- Buffers grow to the largest frame and stay in **memory**. Gradients share rows in one 256x256
  half-float atlas.

## Tips

- Split static and dynamic parts. Draw backgrounds and label shapes once, in one object. Redraw only
  the animated parts every frame.
- Move objects instead of rebuilding them. Animating `position`, `rotation`, `scale` or `alpha` of a
  `SilkGraphics` changes one matrix.
- Reuse gradients. Create them at module scope. Identical ramps share an atlas row anyway, but
  reusing the object avoids re-parsing stops.
- Group primitives that share a layer into one `SilkGraphics` to save draw calls.
- Cap the resolution on large canvases: `createSilkApp({ maxResolution: 2 })`.
- Stop redrawing when idle. Check `Spring.settled`, or redraw only on data changes.
