Skip to content

Unify all marquees on one rAF engine: MarqueeWall + QuickActionWall + fae/mingo/it/sec theme SSOT#1495

Merged
michaelassraf merged 3 commits into
mainfrom
claude/marquee-animation-unify-6058c3
Jul 18, 2026
Merged

Unify all marquees on one rAF engine: MarqueeWall + QuickActionWall + fae/mingo/it/sec theme SSOT#1495
michaelassraf merged 3 commits into
mainfrom
claude/marquee-animation-unify-6058c3

Conversation

@michaelassraf

@michaelassraf michaelassraf commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

What changed

One marquee animation for the whole design system, plus the unified quick-action wall:

  • useMarqueeEngine (hooks/ui) — THE rAF marquee core (float position, velocity envelope, wrap range with getWrapMin, glide), extracted verbatim from CardsStrip. CardsStrip now consumes it; its inline engine and local clone-focus hook are deleted.
  • MarqueeWall (ui) — transform-driven endless wall (no inner scroller): axis x/y, reverse, edge fades via the single MarqueeWallFades component (renders only while content overflows), measured seam wrap (supports CSS-var gaps), useMarqueeSync pixel-locked pairs with driver re-election, trackId offset registry + getMarqueeAppliedOffset/getMarqueeCloneTwin for FLIP-morph coordination (used by the hub deck).
  • QuickActionWall (chat) — the chip wall preset: per-chip fae/mingo/it/sec themes, brick-rows mode (stacked independent row marquees), repeat-padding (minChips), shared skeleton spread (WALL_SKELETON_LABEL_CH), interleave SSOT. QuickActionMarquee is now a thin single-row preset of it (own track-doubling + qa-marquee keyframes deleted from the tailwind config; API moved from duration to px/s).
  • QUICK_ACTION_THEMES — fae/mingo/it/sec accents + lozenges in one map, derived from the same AGENT_ACCENTS source as getAgentAccent; QuickActionChipFromData is the single chip-data mapper (row + wall + marquee).
  • CardsStrip endless-scroll fixes — buffer-zone seam re-centering (fixes leftward scroll sticking 1–2px from the edge while the engine runs) with the buffer capped to the physical scroll slack, and the overflow gate now requires overflow > track gap (prevents a permanent freeze on razor-thin overflow).
  • Clone copies stay clickable with wrapper-level a11y (aria-hidden + focus suppression); Storybook stories added for MarqueeWall and QuickActionWall.

Why

Three competing marquee implementations (CardsStrip rAF, qa-marquee CSS keyframes, static walls with hand-rolled fades) and four chip-wall variants collapsed into one path each — "unify means delete variations".

Reviewer notes

  • Consumed by multi-platform-hub PR (homepage hero walls, FreeTrialCTA strips, company-hub deck slides 3/8): flamingo-stack/multi-platform-hub branch claude/marquee-animation-unify-6058c3 — merge this lib PR first, then release + bump the hub pin.
  • Reviewed by a 5-dimension agent panel to ≥95/100 each (duplication 96, DRY 98, standards 100, logic 96, bug-hunt 99); behavior verified with an instrumented browser audit (landings ≤0.4px, 0ms marquee stalls, endless scroll both directions on the live strips).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added themed quick-action chips with agent accents, IT/SEC classifications, and optional lozenges.
    • Added Quick Action Wall layouts, including stacked brick-wall displays, loading skeletons, fades, and synchronized scrolling.
    • Added configurable marquee speed, direction, hover pausing, minimum chip counts, and reverse movement.
  • Improvements
    • Improved seamless marquee looping, overflow handling, reduced-motion support, and clone accessibility.
    • Updated quick-action marquee configuration from duration-based timing to speed-based control.

… theme SSOT [preview:none]

Co-Authored-By: Claude Fable 5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@michaelassraf, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 770e285b-f3d1-42fb-8ff2-37484db9bf34

📥 Commits

Reviewing files that changed from the base of the PR and between c63e7ce and c1b8e1b.

📒 Files selected for processing (9)
  • openframe-frontend-core/src/components/chat/chat-quick-action-row.tsx
  • openframe-frontend-core/src/components/chat/quick-action-chip.tsx
  • openframe-frontend-core/src/components/chat/quick-action-marquee.tsx
  • openframe-frontend-core/src/components/chat/quick-action-wall.tsx
  • openframe-frontend-core/src/components/features/cards-strip.tsx
  • openframe-frontend-core/src/components/ui/marquee-wall.tsx
  • openframe-frontend-core/src/stories/MarqueeWall.stories.tsx
  • openframe-frontend-core/src/stories/QuickActionMarquee.stories.tsx
  • openframe-frontend-core/src/stories/QuickActionWall.stories.tsx
📝 Walkthrough

Walkthrough

The PR introduces shared marquee animation and synchronization primitives, adds themed quick-action walls with loading and brick-wall layouts, migrates QuickActionMarquee and CardsStrip, and exposes the new components and hooks through barrel exports.

Changes

Marquee and quick-action surfaces

Layer / File(s) Summary
Themed quick-action chip contracts
openframe-frontend-core/src/components/chat/chat-quick-action-row.tsx, openframe-frontend-core/src/components/chat/quick-action-chip.tsx
Quick-action chips support themes, theme-derived accents, boolean or explicit lozenges, icon-spec detection, and shared data-to-button mapping.
Shared marquee engine and wall
openframe-frontend-core/src/hooks/ui/use-marquee-engine.ts, openframe-frontend-core/src/hooks/ui/use-suppress-clone-focus.ts, openframe-frontend-core/src/components/ui/marquee-wall.tsx, openframe-frontend-core/src/stories/MarqueeWall.stories.tsx
Adds reusable animation, clone accessibility, fades, looping, reverse travel, overflow detection, and synchronized wall rendering.
Quick-action wall and marquee integration
openframe-frontend-core/src/components/chat/quick-action-wall.tsx, openframe-frontend-core/src/components/chat/quick-action-marquee.tsx, openframe-frontend-core/src/stories/QuickActionWall.stories.tsx, openframe-frontend-core/src/stories/QuickActionMarquee.stories.tsx, openframe-frontend-core/tailwind.config.ts
Adds padded themed chip walls, brick-wall rows, skeleton states, and migrates marquee configuration from CSS duration to shared px/s speed behavior.
Cards strip engine migration
openframe-frontend-core/src/components/features/cards-strip.tsx
Replaces local marquee animation and clone-focus logic with shared hooks and updates glide and seam-warp handling.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant QuickActionMarquee
  participant QuickActionWall
  participant MarqueeWall
  participant useMarqueeEngine
  QuickActionMarquee->>QuickActionWall: map items to themed chips
  QuickActionWall->>MarqueeWall: render chips, rows, fades, and speed
  MarqueeWall->>useMarqueeEngine: provide pause and wrap configuration
  useMarqueeEngine->>MarqueeWall: apply looping track transforms
Loading

Possibly related PRs

Suggested reviewers: romanivan-flamingo, pavlo-flamingo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: unifying marquee behavior with shared rAF engine and new wall/theme consolidation.
Docstring Coverage ✅ Passed Docstring coverage is 86.36% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/marquee-animation-unify-6058c3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
openframe-frontend-core/src/components/features/cards-strip.tsx (1)

335-343: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Stop the animation engine while the strip is offscreen.

nearViewportRef only feeds isPaused, so useMarqueeEngine continues scheduling rAF callbacks indefinitely while offscreen. Store intersection state in React state and pass active: marqueeActive && nearViewport as MarqueeWall does.

Also applies to: 463-470

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openframe-frontend-core/src/components/features/cards-strip.tsx` around lines
335 - 343, Update the IntersectionObserver logic in the cards strip component to
store the current intersection state in React state instead of only updating
nearViewportRef. Pass an active value combining marqueeActive with the
near-viewport state into useMarqueeEngine, matching MarqueeWall’s behavior, so
animation scheduling stops while the strip is offscreen; update the
corresponding duplicated observer logic as well.
🧹 Nitpick comments (2)
openframe-frontend-core/src/stories/QuickActionWall.stories.tsx (1)

47-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace hardcoded spacing and radius utilities with ODS tokens.

The new story surfaces use p-8, p-4, and rounded-md. Use the corresponding ODS spacing and radius utilities so the examples accurately demonstrate design-system usage.

As per coding guidelines, “Do not use hardcoded styles; translate Figma/Tailwind output and all hand-written styling to ODS tokens.”

Also applies to: 61-61, 90-90

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openframe-frontend-core/src/stories/QuickActionWall.stories.tsx` at line 47,
Replace the hardcoded p-8, p-4, and rounded-md classes in the QuickActionWall
story examples with their corresponding ODS spacing and radius utilities,
including the occurrences referenced near lines 47, 61, and 90. Preserve the
existing layout and styling intent while ensuring all spacing and radius values
use ODS tokens.

Source: Coding guidelines

openframe-frontend-core/src/components/ui/marquee-wall.tsx (1)

185-190: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace hardcoded marquee dimensions with ODS tokens.

The component defaults and stories encode spacing as raw pixel values rather than token-backed CSS lengths.

  • openframe-frontend-core/src/components/ui/marquee-wall.tsx#L185-L190: replace fade-size literals with semantic ODS variables.
  • openframe-frontend-core/src/components/ui/marquee-wall.tsx#L276-L276: replace the numeric copy-gap default with an ODS spacing variable.
  • openframe-frontend-core/src/stories/MarqueeWall.stories.tsx#L52-L52: use a token-backed copyGap.
  • openframe-frontend-core/src/stories/MarqueeWall.stories.tsx#L67-L67: use a token-backed copyGap.
  • openframe-frontend-core/src/stories/MarqueeWall.stories.tsx#L91-L91: use a token-backed copyGap.
  • openframe-frontend-core/src/stories/MarqueeWall.stories.tsx#L111-L112: use token-backed fade and copy-gap values.

As per coding guidelines, raw pixel sizes are not allowed in openframe-frontend-core/src/**/*.{ts,tsx,css}.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openframe-frontend-core/src/components/ui/marquee-wall.tsx` around lines 185
- 190, Replace all raw pixel marquee dimensions with semantic ODS CSS variables:
update DEFAULT_FADE_SIZE in marquee-wall.tsx, the copyGap default near line 276,
and every listed copyGap/fade value in MarqueeWall.stories.tsx. Apply the
appropriate token-backed lengths at marquee-wall.tsx lines 185-190 and 276, and
stories lines 52, 67, 91, and 111-112; make no direct changes elsewhere.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@openframe-frontend-core/src/components/chat/quick-action-marquee.tsx`:
- Line 85: Update the copyGap prop in the quick-action marquee to use the ODS
chip-gap token, passing "var(--spacing-system-xsf)" instead of the hardcoded
value 8 so the clone seam tracks token changes.

In `@openframe-frontend-core/src/components/chat/quick-action-wall.tsx`:
- Around line 185-197: Update the row chip spacing in the MarqueeWall mapping
within the quick-action wall component to use the same copyGap value or CSS
variable already applied to the row stack and clone seam, replacing the fixed
--spacing-system-xsf gap. Preserve the existing fallback behavior so all three
gaps share one pitch.

In `@openframe-frontend-core/src/components/features/cards-strip.tsx`:
- Around line 308-313: Update the overflow state calculation in the cards-strip
sizing logic so any singleCopy width greater than scroller.clientWidth remains
navigable and enables chevrons. Separate this from the marquee/cloning
eligibility check, which may continue requiring overflow beyond TRACK_GAP_PX,
and ensure the static-row path does not suppress navigation for small real
overflow.

In `@openframe-frontend-core/src/components/ui/marquee-wall.tsx`:
- Around line 39-48: Update the MarqueeSyncMember synchronization and
driver-promotion logic around useMarqueeSync so every follower keeps its local
posRef aligned with the shared/current transform. Before starting the engine for
a promoted driver, initialize its position from that synchronized value rather
than its stale local position, preserving continuity when the prior driver
unmounts.

---

Outside diff comments:
In `@openframe-frontend-core/src/components/features/cards-strip.tsx`:
- Around line 335-343: Update the IntersectionObserver logic in the cards strip
component to store the current intersection state in React state instead of only
updating nearViewportRef. Pass an active value combining marqueeActive with the
near-viewport state into useMarqueeEngine, matching MarqueeWall’s behavior, so
animation scheduling stops while the strip is offscreen; update the
corresponding duplicated observer logic as well.

---

Nitpick comments:
In `@openframe-frontend-core/src/components/ui/marquee-wall.tsx`:
- Around line 185-190: Replace all raw pixel marquee dimensions with semantic
ODS CSS variables: update DEFAULT_FADE_SIZE in marquee-wall.tsx, the copyGap
default near line 276, and every listed copyGap/fade value in
MarqueeWall.stories.tsx. Apply the appropriate token-backed lengths at
marquee-wall.tsx lines 185-190 and 276, and stories lines 52, 67, 91, and
111-112; make no direct changes elsewhere.

In `@openframe-frontend-core/src/stories/QuickActionWall.stories.tsx`:
- Line 47: Replace the hardcoded p-8, p-4, and rounded-md classes in the
QuickActionWall story examples with their corresponding ODS spacing and radius
utilities, including the occurrences referenced near lines 47, 61, and 90.
Preserve the existing layout and styling intent while ensuring all spacing and
radius values use ODS tokens.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 26241a9d-60c0-4912-885d-59c4c4425105

📥 Commits

Reviewing files that changed from the base of the PR and between 474d338 and c63e7ce.

📒 Files selected for processing (15)
  • openframe-frontend-core/src/components/chat/chat-quick-action-row.tsx
  • openframe-frontend-core/src/components/chat/index.ts
  • openframe-frontend-core/src/components/chat/quick-action-chip.tsx
  • openframe-frontend-core/src/components/chat/quick-action-marquee.tsx
  • openframe-frontend-core/src/components/chat/quick-action-wall.tsx
  • openframe-frontend-core/src/components/features/cards-strip.tsx
  • openframe-frontend-core/src/components/ui/index.ts
  • openframe-frontend-core/src/components/ui/marquee-wall.tsx
  • openframe-frontend-core/src/hooks/ui/index.ts
  • openframe-frontend-core/src/hooks/ui/use-marquee-engine.ts
  • openframe-frontend-core/src/hooks/ui/use-suppress-clone-focus.ts
  • openframe-frontend-core/src/stories/MarqueeWall.stories.tsx
  • openframe-frontend-core/src/stories/QuickActionMarquee.stories.tsx
  • openframe-frontend-core/src/stories/QuickActionWall.stories.tsx
  • openframe-frontend-core/tailwind.config.ts
💤 Files with no reviewable changes (1)
  • openframe-frontend-core/tailwind.config.ts

Comment thread openframe-frontend-core/src/components/chat/quick-action-marquee.tsx Outdated
Comment thread openframe-frontend-core/src/components/chat/quick-action-wall.tsx Outdated
Comment thread openframe-frontend-core/src/components/features/cards-strip.tsx Outdated
Comment thread openframe-frontend-core/src/components/ui/marquee-wall.tsx
Comment thread openframe-frontend-core/src/components/chat/quick-action-chip.tsx
…all pitch, viewport-gated engine, sync position handoff

- QuickActionChipButton/QuickActionChip/QuickActionWall accept caller-injected theme accents (themeAccent / themeAccents) so server-configured fae/mingo colors override the fallback-only QUICK_ACTION_THEMES map (Michael's review comment)
- QuickActionWall: ONE pitch (copyGap, default var(--spacing-system-xsf)) drives chip gap, clone seam, and brick row-stack gap via new MarqueeWall contentStyle (CodeRabbit major)
- MarqueeSyncController carries the live position; a promoted driver seeds its engine from it instead of teleporting to 0 (CodeRabbit major)
- CardsStrip: viewport now gates the engine's active (rAF fully stops off-screen) instead of being a pause reason; split overflows (chevrons, >1px) from marqueeEligible (>gap) so razor-thin overflow keeps navigation (CodeRabbit major+minor)
- QuickActionMarquee copyGap + story spacing moved to ODS tokens (CodeRabbit minor)

Co-Authored-By: Claude Fable 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant