# Shaders

> Write your own effects, generated backgrounds and transitions as GPU shaders, or start from the shader library: add one from the Effects or Transitions library or as a shader layer, edit its code with errors shown on their lines, give it controls and layer inputs, and share it between layers.

Formats Studio docs · Creative tools · https://formats.app/docs/shaders · Updated 2026-10-20

## What a shader is

A shader is a short piece of code that runs on your GPU for every pixel of a layer. Use one when no built-in effect does what you want: a generated background or texture, a stylised treatment, an image process the catalogue lacks.

- An **effect** shader changes the layer it is on, like any effect in the inspector.
- A **generator** shader paints a layer of its own: a **shader layer** the size of the canvas. It draws only where its layer is, so on text it fills the letters.
- A **transition** shader draws the cut between two clips, like any transition from the Transitions library.
- Shaders belong to the project. Every layer that uses a shader draws the same code, so changing it once changes all of them.
- A shader's controls appear in the inspector like any effect's settings, with keyframes, expressions and audio drivers.

## Add a shader

- **New shader:** open **Effects** in the rail and click **New shader** in the **Shaders** section. It goes on the selected layers, or on a new adjustment layer when **Adjustment layer** is chosen or nothing is selected. **Add** › **Effect layer** in the timeline toolbar has the same **Shaders** category.
- **Shader layer:** click **Add** › **Shape** in the timeline toolbar and choose **Shader layer**, then pick a generator from the shader library, or **New shader** for one of your own. The layer lands on a new top track at the playhead.
- The project's shaders are listed under **Shaders** in both pickers. Click one to put it on a layer; hover it and click the pencil to edit it.
- **Transition shader:** select a clip next to a cut, open **Transitions** in the rail and click **New shader** in the **Shaders** section. The cut's transition draws with a new transition shader (added if the cut has none), and the editor opens on it. The project's transition shaders are listed in the same section: click one, or drag it onto a cut, to draw that transition with it.

Each new shader starts from working code (a grey-out effect, flowing noise between two colours, or a dissolve through noise with a glowing edge), so it draws from the start and the first change you make shows.

## The shader library

The Effects and Transitions pickers and the Shader layer picker list the **shader library**: 138 ready-made shaders, from textures, gradients and shapes to materials, adjustments, blurs, stylised looks, distortions and wipes, grouped by category under **Shader library**. Search finds them by name or category.

- Click one to use it, as you would a project shader. It is copied into your project the first time, and later uses share that copy, so the project keeps its look without the library.
- Library shaders are read-only. Open one in the editor and click **Duplicate and edit** to change a copy of your own.
- Adjustments that change nothing at rest, such as **Exposure** or **Hue shift**, start at the visible setting their tile shows.
- The library is ported from the MIT-licensed shader components of shaders.com by Shader Effects Inc.; some of their noise is MaterialX's (Apache License 2.0), itself adapted from Open Shading Language's (BSD 3-Clause). The full notices are in THIRD_PARTY_NOTICES.md, which ships with the desktop app.

## The shader editor

The editor opens in the side panel, beside a canvas and timeline that stay where they are, so you see every change on the frame as you make it. Open it with **Edit shader** under the effect in the inspector's **Effects** or in a selected shader transition's settings, with the pencil on a shader's tile, or from a clip's shader badge. Close it with the back arrow or by choosing any tab in the rail.

- **Name** and **Description** say what the shader does. The description travels with the project and tells the agent what the shader is for.
- **Colour space:** **Display** hands the code the project's colours as you see them; **Linear light** hands it linear light, where blends and blurs look more natural.
- **Alpha** says what the code returns: **Premultiplied** (the default), **Straight** or **Opaque**.

| Status | Meaning |
| --- | --- |
| **Compiling** | Your change is being checked on the GPU. |
| **Ready** | The shader draws, and every layer using it shows your latest change. |
| **Heavy · 12 ms** | It draws but takes about that long a frame, so playback may stutter. |
| **3 errors** | The code has problems. Nothing has changed: layers keep drawing the last version that worked. |
| **Too slow · 2400 ms** | It would take too long a frame to draw, so it is not used. |
| **Quarantined** | This shader stopped the GPU before, so it is not run again on this computer until you click **Run anyway**. |
| **Shaders off** | The GPU was reset twice this session, so shaders are off until you click **Turn shaders back on**. |

## Writing the code

Shaders are written in WGSL, the language of WebGPU. The code defines one function, `shade()`, which returns the colour of one pixel; everything else is provided.

| Read | What it is |
| --- | --- |
| `fx.uv` | The pixel's place, 0 to 1, across the picture the shader draws on: the whole frame for a shape, text or media layer, the composition for a precomp. |
| `fx.coord`, `fx.size` | The pixel and that picture in pixels. |
| `fx.time`, `fx.layerTime` | Seconds on the composition's clock, and since the layer starts. |
| `fx.frame`, `fx.fps`, `fx.progress` | The frame, the frame rate, and 0 to 1 across the layer. |
| `source(uv)` | The layer the effect is on, at a place across it. |
| `input_<name>(uv)` | Another layer, through one of the shader's layer inputs. |
| `params.<name>` | One of the shader's controls. |
| `fx_noise`, `fx_fbm`, `fx_hash`, `fx_rotate`, `fx_luma`, `fx_sdf_circle`, `fx_sdf_box` | Helpers for noise, random values, rotation, brightness and shapes. |

- Changes apply when you stop typing for a moment; press `⌘Enter` to apply at once. Each change that applies is one Undo step, and typing itself adds none.
- A line with an error gets a red band and a dot by its number; warnings are amber. With the cursor on that line, its message shows under the code, and every problem is listed below it: click one to jump to its line and column.
- While the code has errors nothing is applied, and the layers keep drawing the last version that worked.
- Loops and calls are counted, so a loop that never ends stops instead of freezing your computer, and the shader draws a wrong picture until you fix it.

> **Tip:** Return colours premultiplied: red, green and blue no brighter than alpha. The starting code shows how.

## Transition shaders

A transition shader defines `transition()` instead of `shade()`. It reads the outgoing clip with `getFromColor(uv)` and the incoming clip with `getToColor(uv)`, and `fx.progress` runs from 0 to 1 across the transition, following its **Ease**.

- Select the transition on the timeline to set its controls in the inspector, with **Edit shader** to open its code. Its values belong to that transition; they are not keyframed.
- Duration, placement and ease work as they do for any transition.
- Transition shaders take controls but no layer inputs.
- A transition shader draws on the GPU only. While it compiles or cannot draw, the preview shows a plain cut; an export stops before the first frame instead.

## Passes and compute

An effect or generator shader can run in up to four **passes**, each a function in its code, one after another. A later pass reads an earlier one with `pass_<name>(uv)`, or one exact texel with `pass_<name>_load(px)`, and the last pass is what the layer shows. Blurs, glows and anything that needs the whole picture before it draws are built this way.

- In the shader editor, **Passes** lists them. **Fragment pass** and **Compute pass** add a pass before the last one, with a function that passes the layer through; open a pass to rename it (its function and readers in the code are renamed with it), change its kind or size, or **Show code** to jump to its function.
- A **fragment** pass is `fn <name>() -> vec4f`, run once for each pixel, like `shade()`.
- A **compute** pass is `fn <name>()`. It runs in groups of 64 that can share memory (`var<workgroup>`, 16 KB at most) and wait for each other with `workgroupBarrier()`, and it writes pixels anywhere in its texture with `store(px, color)`: sorting, histograms and sums. Each group covers a region of pixels, 8 × 8 unless you set another; `fx.px` is the pixel an invocation starts at and `fx.index` its place in the group.
- A pass can be drawn at half or a quarter of the layer's size to save time. The last pass is always full size.
- Whole-number counters in shared memory are allowed (`atomicAdd`). A shader whose result depends on which group runs first, such as two groups writing the same pixel, is refused, so every export draws the same.
- Passes start fresh every frame: a pass cannot read what the shader drew on the frame before.

> **Tip:** Barriers must be reached by every invocation of a group: call `workgroupBarrier()` in the compute pass's own function, in loops whose length does not depend on the pixel.

## Controls and layer inputs

**Controls** are the settings a shader shows in the inspector, in the order listed. Choose a type and click **Add control**, then open a control to set its name, range, default, label and description.

| Type | In the inspector | In the code |
| --- | --- | --- |
| **Number** | A slider between Min and Max; Unit Pixels scales it with the render size. | A number. |
| **Whole number** | A slider in whole steps. | A whole number. |
| **Angle** | Degrees, wrapping round 0–360° or clamped to a range. | Radians. |
| **Colour** | A swatch. | A premultiplied colour. |
| **Point** | X and Y, and a handle to drag on the canvas with **Edit on canvas**. | Pixels, like `fx.coord`. |
| **Checkbox** | On or off. | True or false. |
| **Menu** | A choice from its options. | The option's position, from 0. |

- Drag a control by its handle, or focus the handle and use the arrow keys, to reorder it. The code reads controls by name, so reordering never breaks it.
- Renaming a control or input renames it in the code too. A renamed control keeps its values and keyframes, and a renamed input keeps the layer chosen for it.
- Removing a control, or changing its type, drops its values and keyframes in the same Undo step.
- **Layer inputs** read other layers with `input_<name>(uv)`: choose each layer in the effect's settings in the inspector. **Hide the layer** keeps the input layer from showing on its own, as a track matte does. **Required** inputs must have a layer, **Sampling** is smooth or sharp, and **Edges** clamp, repeat or mirror.

## Sharing a shader between layers

**Used by** lists the layers and transitions that use the shader; click one to select it. A change to the shader reaches all of them. To change one layer's look without the others, click **Duplicate for this layer**: that layer moves to a copy of the shader, with its settings and keyframes, and the editor opens the copy. **Duplicate for this transition** does the same for a transition. Changes you have not applied yet go to the copy, not to the others; while the code has errors, fix them first.

## Import a shader from Shadertoy, ISF or GLSL

Shaders written for other sites can come into your project. Open **Effects** in the rail and click **Import shader** in the **Shaders** section (the timeline toolbar's **Add** › **Effect layer** has it too), then paste the code. The editor translates it as you paste and shows what it becomes before anything is added.

| Written for | What to paste | What it becomes |
| --- | --- | --- |
| **Shadertoy** | The Image tab's code (paste a Common tab above it), or Shadertoy's JSON export. | A shader layer. Its time is your layer's time, its mouse is a **Mouse** control you can keyframe (it starts in the corner, as on Shadertoy before a click), and its channels are layers you choose. Choose **An effect** to have it read the layer it is on as its first channel. |
| **ISF** | The whole `.fs` file, with its JSON header. | A shader whose header's inputs become controls: sliders, menus, checkboxes, colours and points, and layers for its images. One that reads `inputImage` is an effect on the layer. |
| **GLSL** | A GLSL Sandbox or Book of Shaders fragment shader. | A shader layer. Time, resolution and mouse are built in; its other uniforms become controls (set their ranges in the shader editor) and its textures become layers you choose. |

- **What its names become** shows each name the code used and what drives it now.
- Anything that cannot come across is listed on its line; click it to select the line. Shaders of several passes (Shadertoy's Buffer tabs), cubemap, sound, keyboard and webcam channels can't be imported yet.
- **Licence:** type the licence and author the shader was shared under, or the editor reads them from the comments at the top of the code. A licence further down usually covers only a snippet pasted in (a noise function, say), so the editor points it out and does not apply it to the whole shader. Shadertoy shaders with no licence stated are under Shadertoy's default, which does not allow commercial use without the author's permission; the editor warns you.
- Add it as a shader layer, to the selected layers, or on a new adjustment layer. The shader editor then shows where it came from and its licence. You can rename it and change its controls' labels, ranges and defaults (a list's options keep their values; their labels change); its code stays as translated. To change the code, click **Import again**, edit it and click **Update**: the shader changes in place, in one Undo step, and controls whose name and type are unchanged keep their values and keyframes. The editor lists any control the new code no longer has before you update.

## When a shader can't draw

- A clip whose shader cannot draw shows a red badge, and the layer shows without the shader; a heavy shader shows an amber one. Click the badge for the reason and **Edit shader**, or **Run anyway** for a quarantined shader.
- Every shader is tried at a small size before it draws at full size, so a shader too slow to draw is stopped before it can freeze the GPU.
- An export never contains a shader that could not draw: it stops before the first frame and says which shader to fix.

## Related

- [Effects and looks](https://formats.app/docs/effects-color): Apply quick Looks, stack GPU effects, import LUTs, and isolate corrections.
- [Transitions](https://formats.app/docs/transitions): Apply a transition or a styled preset to a cut and adjust its style, duration, placement, easing, and direction.
- [Keyframes](https://formats.app/docs/keyframes): Animate transform, crop, text, color, effect, and audio values with keyframes and ready-made animations.
- [Clip properties](https://formats.app/docs/properties): Transform, crop, opacity and blend, and the type-specific controls for each kind of clip.
