File size: 5,581 Bytes
9da4a9b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# 7. Motion

DSSL separates *defining* a motion from *running* it. `motion` defines keyframes. `animate:`
runs one on an element. `seen` and states decide when.

## 7.1 Defining a motion

```dssl
motion rise-in {
  from { opacity: 0; translate: 0 18 }
  to   { opacity: 1; translate: 0 0 }
}

motion pulse {
  essential
  0%   { opacity: 1 }
  50%  { opacity: 0.6 }
  100% { opacity: 1 }
}
```

- **MOT-1.** `motion <name> { ... }` is allowed only at the top level. A motion block holds
  keyframe blocks and the word `essential`. Any other declaration is the error `"<prop>" is
  not allowed inside motion`, with the hint `motions take from/to/at blocks and essential`.
- **MOT-2.** A keyframe block header is one of `from` (0), `to` (100), `at N%` or `N%` or
  `N`, or a comma list of these (`0%, 100%`). Every offset MUST be between 0 and 100. A bad
  header is the error `bad keyframe selector "<h>"`.
- **MOT-3.** `essential` (alone, or as `essential: true`) marks the motion as one that keeps
  playing under `prefers-reduced-motion`.
- **MOT-4.** Declarations inside a keyframe are resolved like any other declaration
  (chapter 6) with `prop` set to the source property. Custom properties are dropped. Each
  output property is named in camelCase (`background-color` becomes `backgroundColor`).
- **MOT-5.** In a keyframe, the deform words (`bend`, `bend-y`, `bend-up`, `fold`, `stretch`)
  are not kept as properties. They are composed into one `transform` (8.5), with an extra
  `transformOrigin` for the edge-pinned ones, because there is no box yet when keyframes are
  built. A deform value of 0 is a real reset.
- **MOT-6.** A list header makes one frame per offset with the same properties. The frames of a
  motion are sorted by offset (a stable sort).
- **MOT-7.** The result is `{ essential: bool, frames: [{ offset, props }] }`. A motion block
  is parsed once, the first time it is needed.

## 7.2 Running a motion

`animate: part, part, ...` or `none`. Each part is `name [words]`.

- **MOT-8.** The spec record starts as
  `{ motion: name, duration: 400, easing: smooth, fill: 'both', delay: 0 }`. `smooth` is the
  `cubic-bezier(0.4, 0, 0.2, 1)` easing from appendix A.
- **MOT-9.** Words after the name are read in order:
  - `delay N`, `jitter N`, `iterations N`: the next word is a number with an optional `ms` or
    `s` unit (for `iterations` a plain count). Missing: error `<word> needs a number`.
  - `essential`: sets `essentialHere`.
  - a number with optional unit: the first word after the name is the duration (`s` means
    seconds, otherwise ms); a later one is the delay.
  - an easing name: sets the easing.
  - `both`, `forwards`, `backwards`, `none`, `auto`: the fill mode.
  - `infinite`: iterations is infinity.
  - `alternate`, `alternate-reverse`, `reverse`, `normal`: the direction.
  - anything else: error `unknown animate part "<w>"`, hint = did-you-mean over the easing
    names and the words above.
- **MOT-10.** One part gives one `@animate` declaration. Several parts (a top-level comma)
  give several, in order. `animate: none` gives `@animate: null`.
- **MOT-11.** After the whole file is walked, every `@animate` with a motion name is linked:
  the motion is looked up in this file, then in the motions the host passed in (7.3). If
  found, the spec gets `frames`, and `essential` is true when the motion or the spec says so.
  If not found, the error is `unknown motion "<n>"`, with a did-you-mean over the file's
  motions, or a hint showing how to define one, and the spec is marked `broken`.
- **MOT-12.** Several `@animate` declarations matched by one element all run, in cascade
  order. `@animate: null` from a later rule cancels the ones before it.

## 7.3 Motions across files

- **MOT-13.** The host passes the already-built motions of earlier files to the resolver (the
  motion registry). A motion defined in an earlier file can be used by a later one, like a
  token. A motion in the current file shadows one in the registry.
- **MOT-14.** After resolving, every motion in the file is built (not only the referenced
  ones) and returned as `motionFrames`, for any consumer that wants all of them (the static
  emitter, 11.4).

## 7.4 The animation shorthand

- **MOT-15.** The plain CSS properties `animation` and `animation-name` pass through (PRP-1,
  item 4), with a bare number meaning ms. If a rule has one whose words do not include the
  name of any motion in this file or the registry, the warning is
  `animation "<v>" references no motion defined in this sheet - it will not run`.
- **MOT-16.** `animation-delay`, `-duration`, `-iteration-count`, `-direction`, `-fill-mode`,
  `-timing-function` and `-play-state` do nothing in a rule that has no `animation` or
  `animation-name`. The warning is `<prop> does nothing here: this rule has no CSS animation
  to tune`, with a hint to put the setting in the `animate:` line.

## 7.5 stagger

`stagger: N` on a parent offsets the delay of each element child's animations by
`index * N` ms, where `index` is the child's position among the parent's element children.

- **MOT-17.** The value is a number with optional `ms` or `s`, or `none`. Anything else is the
  error `stagger needs a duration like "60" or "120ms", or "none"`. It writes `@stagger` with
  milliseconds, or `@stagger: null`.

## 7.6 Reduced motion

- **MOT-18.** When the user prefers reduced motion, a motion plays only if it is `essential`
  (by its own flag or by `essential` on the `animate:` line). Others do not run. Textures,
  auras and tilt follow their own rules in chapter 8.