---
title: derived
description: A read-only value computed from other reads each time a frame resolves.
mode: wide
---

A `derived` is a field computed from other values. It has no setter and stores nothing: each
time a frame resolves, the body runs against that frame's values and its result is the
field's value for the frame.

<DerivedChainScene />

The scene tweens one signal, `elapsed`. `remaining` reads `elapsed`, `label` reads
`remaining`, and `progress` reads `elapsed` again. Scrubbing backwards gives the same numbers
as playing forwards, because every frame computes the chain from that frame's `elapsed`.

## What a body can read

Inside a body, every read returns its value at the frame being resolved:

- the actor's signals, channels and other `derived` fields,
- another actor's fields, read through a reference the actor holds,
- a slot's occupants, through `all()` or `current`,
- `runtime.frame()`, `runtime.timeSeconds()` and `runtime.viewport()`.

The body has to be a function of those reads. `Date.now()`, `Math.random()` or a counter kept
in a module gives a different answer when the same frame is resolved twice, and the
difference shows up when someone seeks. Writing a signal from a body throws
`Cannot set signal "x" during signal resolution`.

## Computing for the renderer

A renderer that draws finished numbers stays simple. Geometry, transforms and labels belong in
`derived` fields, and the renderer reads them:

```ts twoslash title="meter.ts"
import { derived, LayoutActor, signal } from "@motionactor/core";

export class Meter extends LayoutActor {
  level = signal(0);

  fillWidth = derived(() => this.level() * this.localLayout().width);
  caption = derived(() => `${Math.round(this.level() * 100)}%`);
}
```

`localLayout()` is the meter's resolved box, so `fillWidth` follows its layout. The [Desktop example](/docs/examples/desktop)
builds a whole dock this way: icon centres, window transforms and z-order are a chain of
`derived` fields, and the renderer maps over the last one.

## As a spawn input

A spawn input can be a `derived`. The field then follows the computation instead of starting
from a fixed value:

```ts twoslash
import { createScene, derived, LayoutActor, signal } from "@motionactor/core";

class Dot extends LayoutActor {
  x = signal(0);
}

const compiled = createScene(function* (ctx) {
  const leader = ctx.spawn(Dot);
  const shadow = ctx.spawn(Dot, {
    x: derived(() => leader.x() * 0.5),
  });
  yield* leader.x.tween(200, 1);
  return { shadow };
}).build({ viewport: { width: 1920, height: 1080 }, fps: 30 });

compiled.at(30).scene.shadow?.x; // 100
```

To follow a cell as it is, pass it uncalled. The field binds to it, live and read-only, the same
as `derived(() => leader.x())`:

```ts twoslash
import { createScene, LayoutActor, signal } from "@motionactor/core";

class Dot extends LayoutActor {
  x = signal(0);
}

const compiled = createScene(function* (ctx) {
  const leader = ctx.spawn(Dot);
  const echo = ctx.spawn(Dot, { x: leader.x });
  yield* leader.x.tween(200, 1);
  return { echo };
}).build({ viewport: { width: 1920, height: 1080 }, fps: 30 });

compiled.at(30).scene.echo?.x; // 200
```

[`derive`](/docs/reactivity/signal#derive) does the same from the middle of a scene.

On a typed field (`signal.of(type)`), each value the computation produces is checked against the
type, never decoded: a cell holding `"#00ff00"` cannot feed a `colorType` field, which holds a
`Color`. A value that fails throws `TypedFieldValueError`, naming the actor, field, type and value.

## Writing the body

Write the body as an arrow function. `this` is the actor, and inside a resolve it reads that
frame's values. TypeScript infers the type from the body.

A `derived` declared inside a [group](/docs/reactivity/group) cannot read the group it belongs to.
TypeScript reports that the group references itself in its own initializer. Declare the
`derived` next to the group instead, or have it read signals declared outside the group.
