RelayCTX Creative guidelinesGUIDE.motion-register.md
RelayCTX Creative · Document

GUIDE — Motion register

1,469 words · 7 min View raw Source History

GUIDE — Motion register

Status: law — v1, 2026-08-31 Applies to: everything that moves on a Relay surface — estate pages, marketing, product-UI concepts, decks; email is static and stays static Parent: GUIDE.interface-principles.md Pulse family owner: ../briefs/SPEC.pulse-motion.md — ratified; its rules are incorporated by reference here, never restated as a second copy Live lab: ../brand/motion-lab.html — the feedback tier Live specimens: ../concepts/kinetic-type-v1.html — the flourish-on-type tier: rules 1, 3, 4, 5, 6, 7 and 9 each demonstrated as a working specimen, including rule 5's rejected pattern kept live so the rule has a face

Motion on Relay surfaces runs in two layers, and the register keeps them apart:


The pulse family — owned elsewhere, binding here

SPEC.pulse-motion.md is the ratified owner of the pulse family and its four hard rules — one pulsing element per view maximum; product transitions ≤0.18s; everything disables under prefers-reduced-motion; #00D9C8 never loops on product surfaces. They apply in full wherever this register applies. Amendments happen there (the ratification path is in BRIEF.interaction-motion.md); this document only builds around them. If a rule below ever appears to conflict with that spec on a pulse behaviour, the spec wins and this document gets amended.


The register rules

Nine rules. A page that fails one is not finished.

1. CTAs and form inputs never animate and never move

Flourish goes around interactive elements, never on them. A button, link, field, or toggle may carry feedback (≤0.18s state transitions) — it may not drift, shimmer, loop, pulse, or change position. The visitor's target holds still; a moving target is a missed click and a broken promise. Decorative motion that frames an input — ticks, rings, seams adjacent to the control — is the sanctioned pattern. Demonstrated: motion-lab Touch section — press weight and hover answer the hand and stop; the flourish lives in the arrival and waiting demos around them.

2. Play never gates content

Every page is fully readable at rest, mid-animation, and with JS off. No content, navigation, or conversion sits behind a motion moment: nothing waits for an entrance to finish, nothing appears only if a script ran. Motion is applied over finished content, never used to deliver it. Demonstrated: motion-lab — every demo fires on demand over content that is already there; the eggs gallery (/concepts/eggs/) carries the same constraint ("non-essential" is an egg admission rule).

3. Reduced motion gets a complete resting frame — never a blank

prefers-reduced-motion is already law without exception (GUIDE.interface-principles.md, standing rules). This rule sharpens what "disables" means: the reduced-motion view is the finished frame — every element present, opaque, in place — not a blank, not a half-assembled entrance state. An element that fades in must exist at full opacity when motion is off. Pulse hard rule 3's "the static mark must carry the brand alone" is this rule applied to the mark. Demonstrated: motion-lab's reduced-motion block — "demos resolve instantly; loops freeze" — rays and dots land at opacity: 1, decorative rings at opacity: 0.

4. One loud piece per page

The pulse spec caps pulses at one per view; this register caps all loud motion — of any family — at one per page, and a pulsing element counts as the one. Loud means it draws the eye without being asked: a loop, a large entrance, a hero companion. Everything else on the page stays at whisper tier or fires only on interaction. Demonstrated: motion-lab fires demos on demand "for exactly that reason" (its own words) — a page of simultaneous loops would violate the law it teaches.

5. Page-header headlines stay static

The headline is orientation, not theatre. Kinetic type belongs in callouts, section moments, and brand surfaces — never on the line that tells the reader where they are. Provenance is a same-day rejection on the source estate: entrance motion was tried on page headers 2026-08-27 and pulled within hours — "the text plops in on these headers is too much" (Erik, 2026-08-27, Execution Space register record).

6. Scroll-driven over time-driven on informational surfaces

Where someone is reading, motion keys to scroll position, not to a clock: it advances when the reader advances and rests when they rest. Time-driven loops compete with reading and never resolve. Brand surfaces (hero, sign-in, empty states — the pulse spec's loop territory) may be time-driven, inside rule 4's cap.

7. Animate transform and opacity — nothing else, and no motion libraries

Compositor-only properties, so motion never causes layout or jank on a phone. No width/ height/top/left animation (the sheet contract in SPEC.app-components.md — translate, never height — is this rule component-scoped; it is hereby global). No canvas, no WebGL, no ambient-motion or animation libraries — the estate is zero-dependency, no-build, and stays that way. A property outside the pair needs a written exception in the owning spec (the pulse ratification path), not a quiet exemption in CSS. Demonstrated: brand/relay-pulse.css — scale and opacity keyframes, with one exception that took exactly the sanctioned path: rly-burst's mid-frame stroke set is the send-burst colour settle that SPEC.pulse-motion.md ratifies (its hard-moment table: rays fire outward through the pulse colour, settle to teal) — a written exception in the owning spec, not a quiet exemption in CSS. The motion-lab is not claimed as compliant: three of its keyframes (ml-unfold animates clip-path, ml-lift color, ml-nudge border-color) are lab explorations that sit outside the pair and hold no spec exception — they either earn one before shipping to a live surface or ship rebuilt on transform/opacity.

8. Width-dependent pieces are verified at both widths

Any piece whose behaviour depends on viewport width — marquees, rails, travel paths, hero companions — is exercised at a desktop width and a phone width before it ships, not whichever one the builder happened to have open. The source estate got burned exactly here: "we got burned by a marquee that only worked on phones" (Erik, Execution Space handoff, 2026-08) — the desktop failure existed the whole time and only phone-width checks ever ran. Enforcement is the render-verification ritual below.

9. Decorative layers are aria-hidden — the text layer stands alone

Interactive and decorative motion carries content, never replaces it. Every decorative layer (SVG marks, rings, particles, kinetic duplicates of text) is aria-hidden="true", and the plain text layer underneath is complete without it — a screen reader, a text browser, and a JS-off visitor all get the whole page. This is rule 2's assistive-tech half, and the standing fix pattern in ACCESSIBILITY.md (decorative logo SVGs → aria-hidden, not aria-label). Demonstrated: motion-lab — the lockup SVG and demo ornaments are aria-hidden; toasts announce via aria-live, not via their rings.


Enforcement — render verification

The estate's checkers validate text and structure; none of them can see motion. The gate for this register is rendering: before a motion change ships, load the page headless at a desktop width and a phone width (1400 and 390 are the house pair) and verify — zero JS errors, zero horizontal overflow, states exercised at both widths (rule 8), and the prefers-reduced-motion frame checked for completeness (rule 3). This rides the ship-a-bundle checklist in MAINTENANCE.md ("When a new page ships"); a motion change without a two-width render check is not done.


Amending

Same contract as every guideline: rules earn their place by catching real defects. A motion finding that fits no rule here is the signal to amend — change this document in the same PR, cite the incident (EXP-nnn where one exists), add the CHANGELOG.md line. Pulse-family behaviour amends in SPEC.pulse-motion.md, never here. Don't add a rule for a hypothetical.


Provenance

The pulse hard rules were ratified 2026-06-10 (v3.4.1, Session FYBFRY) and carried into v3.5 unchanged — SPEC.pulse-motion.md is their record. Rules 1, 2, 5, 6, and 8 are adapted from the Execution Space estate's motion register — the operating model, not the visual language — where each traces to a dated incident (the 2026-08-27 header pull, the phones-only marquee). Rule 3 sharpens existing law: "disables" alone permitted a blank. Rules 7 and 9 make global what SPEC.app-components.md and ACCESSIBILITY.md already required in the small.


Framework note

Everything here except the pulse-family reference is brand-neutral: the two-layer split, the nine rules, and the two-width render gate apply to any estate with decorative motion — framework-candidate material for Launchpad. The pulse family is Relay's alone; extraction means swapping the owning spec, not untangling the rules.