RelayCTX Kinetic type · K01–K08 · v1

Eight ways type can move, and one place it may not.

Headline and callout motion as working specimens. Play each one, read the wiring line, and copy the markup, never a screenshot. Every piece is one clause of the motion register, demonstrated at full behaviour.

Nothing on this page loops or autoplays, and this headline does not move. Both are the law: one loud piece per page, and the line that tells you where you are stays still.

v1 · 2026-08-31 law: GUIDE.motion-register.md feedback tier: motion lab in the kit open pick

What kinetic type may do here

  1. It may not touch a control. Flourish goes around buttons, links and fields, never on them. A moving target is a missed click. → K08
  2. It may not deliver the content. The words are in the markup and readable at rest, mid-play, and with JS off. Motion is applied over finished prose. → K06
  3. It may not orient the reader. Callouts, section moments and brand heroes are fair game. The page header that says where you are holds still. → K07
  4. It may not run on a clock where someone is reading. On an informational surface, motion keys to scroll and rests when the reader rests. → K04
  5. It may only move transform and opacity. Compositor properties, so a phone never janks. No libraries, no canvas: the estate has no build step and keeps it that way. → K01
  6. It may not be the only copy of the sentence. Split layers carry aria-hidden; a plain twin underneath keeps the prose whole for a screen reader. → K02
K01

Mask rise

in the kit

register rule 7 · transform only, no layout animation

The workhorse. A line sits inside a frame with overflow: hidden and rises into it from below. Nothing animates height or margin, so the paragraph beneath never shifts: the frame is already the finished size before the word arrives. This is the entrance every other specimen is built from.

Callout entrancefires on demand · never loops
Context that moves. The settled beat from the home page, entering as a callout would. At rest it is simply a line of type.
720ms · ease-out-expo
.kt-mask { overflow: hidden } wraps .kt-line { animation: kt-rise } · @keyframes kt-rise { from { transform: translateY(105%) } to { transform: translateY(0) } } · 105% not 100% so descenders clear the frame · the mask carries aria-hidden, a .vh twin holds the sentence
K02

Word stagger vs line rise

open pick

the decision on this page · both are legal, one becomes the default

The same hero, two treatments, playing together so the difference is visible rather than described. A staggers word by word at 45ms; B moves each line as one object. A reads as assembly and draws more attention; B reads as arrival and gets out of the way faster. Stagger is capped either way: ten words at 45ms is 450ms of entrance, and past that a reader is waiting on the page.

A · word stagger45ms apart
Context for AI. When you need it. Where you need it.
B · line rise90ms apart
Context for AI. When you need it. Where you need it.
stagger: style="--i:N" per word · animation-delay: calc(var(--i) * 45ms) · cap the count, not the delay: 10 words is the ceiling, past that reduce the step · one .vh twin per block, not per word — a screen reader should hear a sentence, not eleven fragments
K03

The seal lands

in the kit

register rule 1 · the ring sits beside the Code, never on the control

A Code arriving on a share panel. The characters settle rather than assemble: a 6% scale and a fade, 34ms apart, then a single ring answers next to the seal once the last character lands. The restraint is deliberate and it is a brand rule, not taste. The Code is the wrapper, not the gift, so its arrival is an acknowledgement and never a fanfare. Where sharing is the subject the seal carries the weight of a name that matters, which is what this is: no confetti, no spin, one ring.

Share panel · seal arrivalspecimen Code · not a real relay
Code K4TVX9R2QP, sealed and ready to hand over.
per-character settle, then the ring at 380ms
per-character split needs aria-hidden and a .vh sentence — character spans read letter-by-letter otherwise · kt-settle: opacity + scale(.94 → 1), never rotate · the ring is a sibling of the Code, never a wrapper · presence law: briefs/BRIEF.code-presence.md
K04

Scroll-keyed lines

in the kit

register rule 6 · scroll-driven over time-driven where someone is reading

On a page someone is reading, motion answers to the reader instead of a timer: it advances when they advance and rests when they rest. Scroll inside the frame below and the lines key to your position, backwards as well as forwards. This runs on CSS scroll timelines with no script and no observer, and where the browser has no support the lines simply rest finished, which is the correct frame anyway.

Reader-driven revealscroll inside the frame
Your session doesn’t end when the window does. Every hop, on the record. Context that moves.
on the line: animation-timeline: view() — names nothing, tracks the element in its nearest scrollport · animation-range: entry 12% cover 40% · wrap in @supports (animation-timeline: view()) + prefers-reduced-motion: no-preference, so no-support and reduced-motion both land on the finished line · no JS, no IntersectionObserver, no library
K05

Word swap in place

in the kit

One word changes while the sentence around it holds still. The alternates are stacked in a clipped frame and the stack translates by exactly one line height, so the frame never resizes and the words on either side never reflow. The four here are the product’s own loop steps, so the mechanism is carrying real copy rather than lorem. Step it manually: this is a callout moment, not a carousel, and it never runs on its own.

Section momentstepped by hand · no autoplay

Four steps: connect, package, share, then relay it in.

1 of 4
frame: .kt-swap { overflow: hidden; height: 1.2em } · stack: transform: translateY(calc(var(--kt-slot) * -1.2em)) · the em step and the frame height are the same number, or the words drift · transition, not an animation loop — a swap that runs itself is a carousel and breaks rule 4
K06

The resting frame

in the kit

register rule 3 · reduced motion gets the finished frame, never a blank

The specimen that is not a motion. Switch the page into its reduced-motion state and every piece above lands where it would have finished: present, opaque, in place. This is the failure the rule exists to catch, because the natural way to write an entrance leaves the element at opacity: 0 when the animation never runs, and the visitor who asked for less motion gets an empty page instead. Toggle it and scroll back up: nothing disappears.

Simulated prefers-reduced-motionaffects the whole page
Motion on. Specimens play when asked.

The switch adds one class to <html> and mirrors what the media query does for real. It is here so the frame can be inspected without changing an operating-system setting, which is the reason this failure usually ships unseen.

write entrances so rest is the finished state and the animation only plays under a class · never opacity: 0 in the base rule · the media query sets animation: none; opacity: 1; transform: none · verify by rendering with reduced motion emulated, not by reading the CSS
K07

Where it may not go

rejected pattern

register rule 5 · kept live so the rule has a face

A page header assembling itself word by word. It is competent motion and it is banned here, which is the distinction worth keeping visible: brand heroes may move, and the line that tells a reader where they are may not. It was tried on the source estate and pulled the same day.

Do not ship thisdemonstration only

Example page header: Operations, session coordination.

70ms apart, and already too much
The record: entrance motion on page headers was tried on the Execution Space estate on 2026-08-27 and pulled within hours — “the text plops in on these headers is too much” (Erik, 2026-08-27). A header is orientation. A reader arriving mid-task reads it before the animation finishes, so the motion is either invisible or in the way.
K08

The assembled callout

in the kit

register rules 1 and 4 · one loud piece, and nothing loud on the control

The pieces working together as a real section would use them: mask rise on the head, the supporting line following at 260ms, and a call to action that does not move at all. This is the whole budget for a page. If a section like this is on the page, everything else stays at whisper tier or waits to be asked.

Marketing section · full assemblythe page’s one loud piece

The idea

Your session doesn't end when the window does. Close the laptop mid-thought. Open a different tool tomorrow. The work you were in is still there, still yours, and loads where you are now. Get access
the button is inert here · it never animates
head rises, sub follows at 260ms — support never leads · the CTA has no entrance and no transform: it is the target, it holds still · one assembly of this weight per page · copy is canon: copy/relay-web-copy.md
Kinetic type · v1 · 2026-08-31 Law: GUIDE.motion-register.md Feedback tier: motion lab Eggs: the gallery Sibling: forms kit