> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryablo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Shape & Layer Fills — Colors, Gradients, and Images

> Use the fill builders to paint shapes and layers with solid colors, linear or radial gradients, mesh gradients, image fills, and animated shader effects.

Fills define how a shape or layer is painted. Every fill builder in `@abloatai/decks` returns a `Fill` object that you place in a layer's `fills` array. Fills are composited from bottom to top — so the first entry in the array sits at the back and each subsequent entry layers on top — giving you the same stacking model as Figma. The SDK ships six builders covering the four fill types: `'solid'`, `'gradient'`, `'image'`, and `'shader'`.

```typescript theme={null}
import {
  shape,
  solidFill,
  linearGradient,
  radialGradient,
  meshGradient,
  imageFill,
  shaderFill,
} from '@abloatai/decks';
```

***

## solidFill

`solidFill(color, opacity?)` returns a flat, single-color fill. Pass any CSS color string — hex, `rgb()`, `rgba()`, or a theme CSS variable — and an optional opacity multiplier between `0` and `1`.

```typescript theme={null}
// Opaque brand color
solidFill('#5B4CF5')

// 50 % transparent via rgba + opacity shorthand
solidFill('rgba(91,76,245,0.5)', 0.5)

// Theme token reference
solidFill('var(--slide-brand)')
```

<Tip>
  You can use `colorRef('brand')` from `@abloatai/decks` to produce `'var(--slide-brand)'`
  without typing the CSS variable name by hand.
</Tip>

***

## linearGradient

`linearGradient(stops, opts?)` sweeps a gradient along a straight line at `angle` degrees (default `180`, which runs top→bottom). Each stop is a `{ color, at? }` object where `at` is a `0`–`1` position along the gradient axis.

<ParamField path="stops" type="{ color: string; at?: number }[]" required>
  Gradient color stops in order. Omit `at` to let the browser distribute stops evenly.
</ParamField>

<ParamField path="opts.angle" type="number">
  Angle in degrees. `0` = bottom→top, `90` = left→right, `180` = top→bottom (default), `270` = right→left.
</ParamField>

<ParamField path="opts.opacity" type="number">
  Overall fill opacity from `0` to `1`. Defaults to `1`.
</ParamField>

```typescript theme={null}
// Two-stop diagonal gradient
linearGradient(
  [{ color: '#5B4CF5' }, { color: '#EEF0FF' }],
  { angle: 135 },
)

// Three-stop top-to-bottom with explicit positions
linearGradient(
  [
    { color: '#0066CC', at: 0 },
    { color: '#5B4CF5', at: 0.5 },
    { color: '#EEF0FF', at: 1 },
  ],
  { angle: 180, opacity: 0.9 },
)
```

***

## radialGradient

`radialGradient(stops, opts?)` radiates outward from a center point. The optional `at` option is an `[x, y]` pair in `0`–`1` canvas coordinates (`[0.5, 0.5]` is the center).

<ParamField path="stops" type="{ color: string; at?: number }[]" required>
  Color stops along the radial axis from center to edge.
</ParamField>

<ParamField path="opts.at" type="[number, number]">
  Center of the gradient as `[x, y]` fractions of the fill box. Defaults to the CSS default (centered).
</ParamField>

<ParamField path="opts.opacity" type="number">
  Overall fill opacity from `0` to `1`. Defaults to `1`.
</ParamField>

```typescript theme={null}
// White center fading to brand color, centered
radialGradient([
  { color: '#fff', at: 0 },
  { color: '#5B4CF5', at: 1 },
])

// Off-center glow in the top-left quadrant
radialGradient(
  [{ color: '#EEF0FF', at: 0 }, { color: 'transparent', at: 1 }],
  { at: [0.2, 0.2] },
)
```

***

## meshGradient

`meshGradient(points, opts?)` layers multiple positioned radial blobs to create a soft, organic mesh effect — the kind of blurred color-cloud background common in modern design. Each point is an `{ color, at, radius? }` object where `at` is an `[x, y]` position in `0`–`1` coordinates and `radius` controls the blob's spread as a fraction of the fill box (default `0.5`).

<ParamField path="points" type="{ color: string; at: [number, number]; radius?: number }[]" required>
  Positioned color blobs. Each renders as a radial gradient and all layers are composited together.
</ParamField>

<ParamField path="opts.background" type="string">
  An optional CSS color placed behind all the blobs as a solid base.
</ParamField>

<ParamField path="opts.opacity" type="number">
  Overall fill opacity from `0` to `1`. Defaults to `1`.
</ParamField>

```typescript theme={null}
meshGradient(
  [
    { color: '#5B4CF5', at: [0.15, 0.2],  radius: 0.55 },
    { color: '#6EE7F9', at: [0.75, 0.15], radius: 0.45 },
    { color: '#EEF0FF', at: [0.5,  0.85], radius: 0.6  },
  ],
  { background: '#0D0B1F' },
)
```

<Note>
  `meshGradient` compiles to stacked `radial-gradient` CSS layers. It works in every modern
  browser without any runtime dependency.
</Note>

***

## imageFill

`imageFill(url, opts?)` stretches an image over the fill box. Use `ablo.images.upload()` to get a hosted URL for local files before passing it here.

<ParamField path="url" type="string" required>
  A fully-qualified `https://` URL for the image. Must be one of the accepted MIME types:
  JPEG, PNG, GIF, WebP, SVG, or AVIF.
</ParamField>

<ParamField path="opts.objectFit" type="'cover' | 'contain' | 'fill'">
  How the image fits its box. `'cover'` (default renderer behavior) crops to fill; `'contain'` letterboxes; `'fill'` stretches without preserving aspect ratio.
</ParamField>

<ParamField path="opts.opacity" type="number">
  Overall fill opacity from `0` to `1`. Defaults to `1`.
</ParamField>

```typescript theme={null}
// Full-bleed cover image
imageFill('https://cdn.example.com/hero.jpg')

// Contained image at 80% opacity
imageFill('https://cdn.example.com/logo.png', {
  objectFit: 'contain',
  opacity: 0.8,
})
```

***

## shaderFill

`shaderFill(input, opacity?)` applies an animated WebGL gradient powered by a named preset. The shader runs in the Ablo renderer and produces smooth, continuously animating backgrounds — no extra dependencies required on your end.

<ParamField path="input.preset" type="ShaderPreset" required>
  One of `'aurora'`, `'ocean'`, `'sunset'`, `'ember'`, `'midnight'`, `'mint'`, `'candy'`, or `'custom'`.
</ParamField>

<ParamField path="input.colors" type="{ color1: string; color2: string; color3: string }" required>
  Three CSS color strings that the shader blends together. Exact behavior varies by preset.
</ParamField>

<ParamField path="input.speed" type="number">
  Animation playback speed. Defaults to `0.2`.
</ParamField>

<ParamField path="input.density" type="number">
  Pattern density / frequency. Defaults to `1.3`.
</ParamField>

<ParamField path="input.animate" type="boolean">
  Whether the shader animates. Set to `false` for a static snapshot. Defaults to `true`.
</ParamField>

<ParamField path="opacity" type="number">
  Overall fill opacity from `0` to `1`. Defaults to `1`.
</ParamField>

<CodeGroup>
  ```typescript Aurora preset theme={null}
  shaderFill({
    preset: 'aurora',
    colors: {
      color1: '#5B4CF5',
      color2: '#6EE7F9',
      color3: '#EEF0FF',
    },
    speed: 0.3,
    animate: true,
  })
  ```

  ```typescript Static sunset theme={null}
  shaderFill(
    {
      preset: 'sunset',
      colors: {
        color1: '#FF6B6B',
        color2: '#FFE66D',
        color3: '#FF8E53',
      },
      animate: false,
    },
    0.9,
  )
  ```
</CodeGroup>

***

## Using fills on shapes

The `fills` field on a `shape` layer accepts an array of `Fill` objects. The fills composite bottom-to-top, so you can combine a solid base with a gradient or image overlay in a single layer.

```typescript theme={null}
import { shape, meshGradient, solidFill } from '@abloatai/decks';

const heroBackground = shape({
  shape: 'rectangle',
  fills: [
    // Base color sits at the bottom of the stack
    solidFill('#0D0B1F'),
    // Mesh gradient composited on top
    meshGradient(
      [
        { color: '#5B4CF5', at: [0.15, 0.2],  radius: 0.55 },
        { color: '#6EE7F9', at: [0.8,  0.15], radius: 0.45 },
        { color: '#EEF0FF', at: [0.5,  0.9],  radius: 0.6  },
      ],
      { opacity: 0.7 },
    ),
  ],
  at: { x: 0, y: 0, w: 1920, h: 1080 },
});
```

<Warning>
  Image fills require a hosted URL. Passing a `data:` URI or a local file path will fail
  schema validation. Upload the file first with `ablo.images.upload()` and use the returned URL.
</Warning>
