Advanced · Generic tween

Name the properties, not the effect.

Fifteen properties, two directions. Compiled to real CSS keyframes.

Monochrome teal portrait in a curved sculptural hat

data-kui="tween-from y:64px rotate:-7deg scale:0.88 opacity:0 1100ms expo-out on:load"

Arbitrary values. Still not JavaScript.

A block with only a to step gets its from from the element itself.

press
click the block
data-kui="tween x:96px rotate:12deg scale:1.12 900ms on:click"

1 you write

<div data-kui="tween
  x:96px
  rotate:12deg
  scale:1.12
  900ms on:click">

2 the compiler writes — live

3 the browser interpolates

@keyframes kui-tween-to-translate {
  to {
    translate:
      var(--kui-tween-x, 0)
      var(--kui-tween-y, 0)
      var(--kui-tween-z, 0);
  }
}
/* no `from` step */

Fifteen properties, one block.

One shared target — click a chip and the compiled keyframes swap under it.

Beauty portrait with white curls, cobalt lips and blue fur gloves framing the face tween

data-kui="tween-from x:-160px 900ms expo-out"

A property is written whole — an axis you don't name returns to its initial value.

To, and from

Same values, opposite ends — GSAP's .to()/.from() pair, in CSS.

to

data-kui="tween x:120px opacity:0.15 rotate:24deg 700ms"

Channels come off your attribute. tween-from scale:0.5 composes with fade-in; tween-from y:120px collides with it, because fade-in owns translate too.

What we won't animate, and why

widthheighttopleft

All four animate layout. The tween declares perfClass: 'paint'.

Instead: flip-reorder, accordion-height, grid-to-list

rotate-xrotate-y

CSS's rotate takes one axis at a time, and perspective lives in the transform shorthand — a different channel.

Instead: flip-in-x, flip-in-y

skew

Same shorthand problem — and there is no skew property to write.

Instead: the named effects that own the shorthand

tween

Any named property, A to B.

FLIP

Moves it because the layout changed.

motion-path

Moves it along a curve you draw.

Animating into and out of the DOM

Six names that animate a display: none element. Manual by construction — pick one, then open it.

Opacity only.Manual by construction — click Open to preview.

data-kui="fade-open"

A [data-open] attribute is the trigger — discrete.css's closed-state rule matches :not([data-open]), and transition-behavior: allow-discrete keeps the element rendered on the way out.

three ways to drive one — [data-open] above, plus these two

Native popoverNo page JavaScript.
data-kui="pop-open 320ms" on a [popover] — driven by :popover-open
Native <dialog>Driven by [open].
data-kui="slide-open-up 320ms" on a <dialog> — driven by [open]

A form control is just an element

on:focus/blur is a trigger pair — the second half reverses the first.

Every field cascades in

data-kui="tween scale:1.03 brightness:1.08 220ms on:focus/blur"

Purpose-built form effects also ship — label-float input-underline-grow focus-ring-grow checkbox-draw radio-fill range-fill toggle-morph strength-meter validate-check validate-shake step-progress submit-to-spinner-to-check