---
title: "Motion tokens"
description: "The `easings` and `transition` collections and how components consume them."
requested_language: cs
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/cs/next/design/motion-tokens
version: unreleased (main)
docs_index: https://docs.systhema.app/cs/next/llms.txt
---
> This page isn't translated yet. Showing English.


Systhema ships a built-in table of [easing curves](https://docs.systhema.app/cs/next/styling/easing.md), and it stays one. Two **optional** token collections put motion in Figma's hands on top of it:

## Collections

| Collection   | Holds                                                                     | Emitted as                                                       |
| ------------ | ------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `easings`    | `$type: 'easing'` curves and `$type: 'duration'` speeds at its root       | `--ease-<name minus its leading "ease">` and `--duration-<name>` |
| `transition` | Per-component values, one branch per component (`button.primary.*` today) | `--transition-<kebab dot-path>`                                  |

So `easeOutCubic` becomes `--ease-out-cubic`, `defaultTransitionSpeed` becomes `--duration-default-transition-speed`, and `button.primary.transitionDuration` becomes `--transition-button-primary-transition-duration`. All three land on `:root` in the base layer, from the same plugin — there is exactly one declaration site for `--ease-*`.

**What Systhema's own export ships is `easings`, curves only.** There is no shipped `transition` collection and no shipped duration: those are values a project's designer authors, and generating them would hand every project a motion language nobody chose. Both are read whenever a project's Figma file declares them — export a `transition` collection or a Timing variable and the custom properties appear, with no code change on either side. Until then every component computes the fallback written into its own `var(--transition-…, <initial>)` reference, which is what it computed before the collections existed.

A `transition` token that aliases an `easings` one keeps the reference: the variable is written as `var(--ease-out-cubic)` / `var(--duration-default-transition-speed)`, mapped by the **target token's declared type**, not by its name.

## The built-in fallback

The built-in table is the fallback, per curve. A project's `easings` collection is merged OVER it, so:

- no `easings` collection at all → exactly the built-in curves, unchanged;
- a collection that declares `easeOutCubic` → that curve wins for both `.ease-out-cubic` and `--ease-out-cubic`;
- a collection that is missing one (the shipped export has no `easeInOutQuad`) → the built-in curve still ships.

## Wiring a component

Only the button reads these today. The pattern for any other component is the same three declarations, each with the value the component computed BEFORE the collection existed as its fallback:

```ts
transitionProperty: `var(--transition-button-${type}-transition-property, color, background-color)`,
transitionDuration: `var(--transition-button-${type}-transition-duration, 0s)`,
transitionTimingFunction: `var(--transition-button-${type}-transition-timing-function, ease)`,
```

`0s` and `ease` are the CSS initial values, so a project with no `transition` collection — which is every project that has not exported one — computes exactly what it did before. A consumer utility (`duration-300 ease-out-cubic`) still wins over all of it: utilities are unlayered inside `utilities`, and these sit in the `utilities.systhema` sub-layer.

Note that a `transitionProperty` token replaces the curated property list outright.
