# BRIEF.interaction-motion.md — Pulse Family, Interaction Layer
**Project:** relay-creative / brand motion exploration
**Status:** exploration — nothing here is ratified until it lands in `SPEC.pulse-motion.md`
**Live lab:** `/brand/motion-lab.html` (interactive demos of everything below)
**Gallery:** `/gallery.html` (the riff wall — mastheads, animatics, eggs, motion, one room)
**Date:** July 2026 · v3.5 neutral-first

---

## Why

`SPEC.pulse-motion.md` ratified six behaviours (heartbeat, receipt flash, send burst,
awaiting, arrival ring, broadcast) and gave `#00D9C8` its job: motion-only, event
flashes, never static, never looping on product surfaces. `BRIEF.animations.md`
covers the *produced* marketing motion (Lottie/MP4 stings, deck beats, social cuts).

The gap between them is the **interaction layer**: how creating, copying, sending,
claiming, and waiting feel *inside the app*. This brief proposes eight additions to
the pulse family to fill it. All obey the four hard rules unchanged.

## The four hard rules (carried verbatim, not renegotiated)

1. One pulsing element per view, maximum.
2. Product UI transitions stay ≤0.18s — pulse moments are event animations (once)
   or brand-surface loops, never product chrome.
3. Everything disables under `prefers-reduced-motion`. The static mark must carry
   the brand alone.
4. Never loop #00D9C8 on product surfaces. Looping pulses stay in system teal;
   #00D9C8 is reserved for event flashes.

## Proposed additions (7–14)

| # | Moment | Class | Behaviour | Loop? | Colour law | Where |
|---|--------|-------|-----------|-------|-----------|-------|
| 7 | Code materialize | `.rly-materialize` | Characters land top-down, 55ms stagger, 0.3s each | Once | system teal | The moment a relay is created and its Code is minted |
| 8 | Copy cascade | `.rly-copy-cascade` | Characters lift in a 28ms wave; one #00D9C8 underline sweep | Once | **#00D9C8** · event | Code copied (the most repeated act in the product) |
| 9 | Claim unfold | `.rly-unfold` | Received card wipes open (clip-path), content lines stagger in 90ms apart | Once | system teal | Relay received / context loaded |
| 10 | Stream arrival | `.rly-stream-in` | Item slides in from above (0.4s out-expo); status dot carries one arrival ring | Once | **#00D9C8** ring · event | Stream feed, new item |
| 11 | Routing spinner | `.rly-routing` | Mark rays chase clockwise, 1.1s, eight steps | **Loop** | system teal (rule 4) | Network waits over 400ms; replaces generic spinners |
| 12 | Shutter toggle | `.rly-shutter` | Rays open/close clockwise, 30ms steps, on a boolean setting | Once | system teal | Settings that turn a signal on: notifications, nudges, visibility |
| 13 | Nudge blink | `.rly-nudge` | Two soft border-and-dot beats, 1.1s total, then still | Once (2 beats) | system teal | A nudge arrives — a tap on the shoulder, not an alarm |
| 14 | In-flight travel | `.rly-travel` | Code chip crosses a dashed path through the mark; pulse-coloured while moving | Once, bounded | **#00D9C8** · in motion | Brand surfaces + send confirmation; the lab's lifecycle hero |

Timing conventions across all eight: out-quart/out-expo easing, no bounce, no
elastic; exits run ~75% of entrance duration; product-layer feedback stays ≤0.18s
(press weight is 0.12s at scale 0.97).

## Colour-law notes

- 8, 10, 14 use #00D9C8 and all three are **bounded events**: a sweep that dies,
  one ring, one flight. None loops. Rule 4 holds.
- 11 (routing spinner) loops, so it stays system teal even though "something is
  happening right now" — the something is *waiting*, not *arriving*. When the wait
  resolves, the arrival moment (receipt flash, family 2) carries the #00D9C8.
- 13 (nudge) deliberately does NOT use #00D9C8: a nudge is a request, not a
  receipt. Keeping it system teal preserves the meaning "pulse colour = context
  crossed a boundary."

## Relationship to the eggs (PR #34) and animatics

- Egg D (Code scramble) stays as-is; materialize (7) is its creation-time cousin.
  Scramble is hover-play, materialize is a birth event. They never run on the same
  element at the same time.
- Egg E (status snap) and F (receive beam) already own the receive moment on their
  surfaces; claim unfold (9) is the app-card variant, not a replacement.
- The animatics (`/animatics.html`) remain the produced marketing layer. 14
  (in-flight travel) is the in-app, code-drawn cousin of the M06 Send→Route→Receive
  sting — same grammar, so the app and the marketing motion rhyme.

## Ratification path

1. Team plays with `/brand/motion-lab.html` (light + dark, desktop + mobile).
2. Cut or amend concepts; anything kept gets its row appended to the family table
   in `SPEC.pulse-motion.md` and its keyframes added to `brand/relay-pulse.css`
   (bump to v3.5.1).
3. Product adoption lands via relay-app tickets referencing the class names above.

## Open questions

- Does the routing spinner replace *all* spinners, or only relay-specific waits?
  (Recommendation: relay-specific first; global adoption after it proves calm.)
- Should copy cascade fire on keyboard copy (Ctrl/Cmd-C on a focused Code) as well
  as click? (Recommendation: yes — same event, same acknowledgement.)
- Stream arrival under rapid bursts: cap at one ring per 2s per feed so a busy
  Stream never strobes. Needs a debounce rule in the spec if ratified.

---

*relay-creative/briefs/BRIEF.interaction-motion.md · July 2026 · exploration*
