dssl / native /spec /07-motion.md
EHS-Studio's picture
Claude Sonnet 5.5
v0.16.3: native DSSL spec, and the seven bugs writing it found
9da4a9b
|
Raw History Blame Contribute Delete
5.58 kB

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

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.