---
title: Reactivity
description: Writable state, computed reads, host-published values and coordination are separate primitives. Picking the right one is most of actor design.
---

The runtime deliberately refuses to give you one general-purpose reactive box. Each
primitive encodes a different claim about where a value comes from and who is allowed to
change it — which is what keeps frame resolution pure.

## Choosing a primitive

**[Signals](/docs/reactivity/signal)**

One flat writable value. The default.

**[Reactive signals](/docs/reactivity/reactive-signal)**

One nested state bag whose leaves animate independently.

**[Derived values](/docs/reactivity/derived)**

Read-only, computed from other reads.

**[Channels](/docs/reactivity/channel)**

A value the host publishes, not the timeline.

**[Groups](/docs/reactivity/group)**

Namespaces related fields into one surface.

**[Overlay and offset signals](/docs/reactivity/overlay-signal)**

Layers transient motion over a base value.

**[Watch](/docs/reactivity/watch)**

Actor-local reactive response.

**[Events and subscribe](/docs/reactivity/events-and-subscribe)**

Typed coordination between actors.

## The decision, in one pass

Ask these in order. The first *yes* is your answer.

| Question | Primitive |
| --- | --- |
| Is the value computed from other reads and never set directly? | [`derived`](/docs/reactivity/derived) |
| Is the value *observed* rather than authored — measured, fetched, simulated, sensed? | [`channel`](/docs/reactivity/channel) |
| Is it a nested bag whose individual leaves need to animate on their own? | [`reactiveSignal`](/docs/reactivity/reactive-signal) |
| Is it transient motion sitting on top of a canonical value? | [`overlaySignal`](/docs/reactivity/overlay-signal) |
| Anything else the timeline writes | [`signal`](/docs/reactivity/signal) |

Two of these are not state at all. [`group`](/docs/reactivity/group) is namespacing, and
[`events`](/docs/reactivity/events-and-subscribe) are coordination — reach for them when
the question is "how do I organize this" or "how does another actor find out", not "where
does this value live".

:::info[The signal / channel line]
  If the value's history is **authored** — `set`, `tween`, `play` — it is a signal. If the
  value is **observed** — measured, fetched, simulated, sensed — it is a channel. This is
  the one distinction worth memorizing; almost every determinism bug is a channel value
  that was modelled as a signal.
:::

## Ownership

Owners mutate their own canonical state. Non-owners emit semantic intents and let the
owner decide.

```ts
// Wrong — reaching through another actor to write its state.
playButton.onPress(() => video.playback.currentTime.set(0));

// Right — emit intent, the owner responds.
subscribe(video, playButton, {
  *pressed() {
    yield* this.restart();
  },
});
```

That rule is what lets an actor be reused: it keeps every write to a piece of state inside
the class that declared it, so its invariants hold no matter who is driving.
