#303
Infinite marquee
A row of partner names sliding left forever at a constant speed, with a seamless loop. Hovering or focusing any name pauses it; Back and Forward buttons nudge it once you take over.
Hand this to your AI. It names the exact library parts, timings and accessibility promises of this demo.
Build the "Infinite marquee" pattern (@codeatlasdev/ui demo #303, motion/text) in my app.
Call get_demo({ ids: ["#303"] }) first and keep its structure. It needs @codeatlasdev/[email protected].
Use: Logo walls, customer and press strips, announcement tickers and feature tags that should stay visible without taking space or a carousel.
Keep these library parts, with the props and tokens the demo uses:
- Button, MotionStage from "@codeatlasdev/ui"
Behaviour to keep:
- `MotionStage` from `@codeatlasdev/ui` with `label="Marquee: partner names scroll endlessly and pause on hover or focus"` and `loop={4000}`
- `animation: mq-slide 18s linear infinite` on the track while `m.playing && !m.reduced`
- Keyframes: `from { transform: translateX(var(--nudge)); }` to `to { transform: translateX(calc(var(--nudge) - 50%)); }`
- The list is rendered twice; the second copy is `aria-hidden="true"` with `tabindex="-1"` so the loop is seamless and read once
- `.mq__viewport:hover .mq__track` and `.mq__viewport:focus-within .mq__track` set `animation-play-state: paused`
- The `Button` `onclick` handlers change `nudge` by 56px, the manual takeover
- Under reduced motion `m.playing` is false, so the strip stays static and every name is readable
Exact motion (do not approximate):
- transform: translateX (the track moves -50% of its own width): 18s, linear
- transform: translateX (manual nudge after takeover): 240ms, cubic-bezier(0.2, 0, 0, 1)
Reduced motion: the demo handles it; keep that branch.
Keyboard: operable; keep the focus order and key handling.
Change only the copy and the data. Use the theme tokens (--ca-*), never raw colours. Library parts
- Button
@codeatlasdev/ui - MotionStage
@codeatlasdev/ui
How it is built
- `MotionStage` from `@codeatlasdev/ui` with `label="Marquee: partner names scroll endlessly and pause on hover or focus"` and `loop={4000}`
- `animation: mq-slide 18s linear infinite` on the track while `m.playing && !m.reduced`
- Keyframes: `from { transform: translateX(var(--nudge)); }` to `to { transform: translateX(calc(var(--nudge) - 50%)); }`
- The list is rendered twice; the second copy is `aria-hidden="true"` with `tabindex="-1"` so the loop is seamless and read once
- `.mq__viewport:hover .mq__track` and `.mq__viewport:focus-within .mq__track` set `animation-play-state: paused`
- The `Button` `onclick` handlers change `nudge` by 56px, the manual takeover
- Under reduced motion `m.playing` is false, so the strip stays static and every name is readable
Related
Loading source.