Skip to content

feat: motion polish across ui, playground, code - #3243

Merged
smakosh merged 1 commit into
mainfrom
feat/motion-polish
Jul 26, 2026
Merged

smakosh merged 1 commit into
mainfrom
feat/motion-polish

Conversation

@smakosh

@smakosh smakosh commented Jul 26, 2026 •

Copy link
Copy Markdown
Member

Summary

Implements the 10 highest-leverage opportunities from a full animation audit of apps/ui, apps/playground, and apps/code, gated on Emil Kowalski's frequency/purpose/speed/function framework. Every candidate that failed the gate (keyboard-driven surfaces, data being read, nav pills, modal origins) was deliberately left alone.

What changed

Surface Change
All four shared Buttons (ui, playground, code, shared) active:scale-[0.98] press feedback — nothing in any app responded to press before
playground PopoverContent added the missing origin-(--radix-popover-content-transform-origin) — the 720px model picker now grows from its trigger like every sibling primitive
ui Radix toast exits the same edge it enters (bottom on desktop, top on mobile); swipe-dismiss keeps its rightward exit via a not-data-[swipe=end] variant
DevPass activation (DashboardShell) spinner+toast replaced with a "DEVPASS ACTIVATED" visa stamp (house spring, { type: "spring", duration: 0.4 }), success screen held 1.6s (abort-safe) before the dashboard swap
Reset Pass purchase (ResetPassCard) purchase now slams the full-card stamp the copy always promised (indigo "PASS ACQUIRED" with the charge amount folded in); duplicate success toast removed
Lounge points pill odometer-style digit roll on value change (250ms, [0.16,1,0.3,1]), streak flame crossfade — the core gamification loop is finally visible
Copy buttons (ui markdown code blocks, playground code blocks, code QuickStart + models showcase) 150–160ms icon crossfade instead of instant swaps; QuickStart label width jump fixed
playground Chats section grid-rows height transition matching the chevron that always rotated; transition suppressed on hydration so cookie-collapsed users don't watch it close on load
playground credits dialog the stamp-shaped "CREDITS ADDED" badge now stamps in
Census /data/[year] motion-safe: staggered entrance (70ms steps) for hero, stats, and the first 10 registry rows — deep rows render instantly

All new movement has prefers-reduced-motion fallbacks (fade-only, never zero feedback). Only transform/opacity are animated except the Chats collapse, which is an interruptible accordion-style transition confined to the sidebar subtree.

Review

Ran an adversarial review against the repo's review-animations bar; its findings (diagonal toast swipe exit, untransitioned press scales on raw buttons, reduced-motion gaps, split stamp physics, stamp+toast double-fire, collapse replay on hydration) are all fixed in this diff. Two conscious accepts: the pre-existing transition-all on the shared Button cva is left as-is (stock shadcn; scoping it repo-wide is a separate change), and the points pill snaps ~2ch wider at digit-count boundaries (rare; the fixes are all worse).

Test plan

  • turbo run build --filter=ui --filter=playground --filter=code ✓ (15/15)
  • pnpm test:unit ✓ (3053 passed)
  • pnpm format / lint-staged ✓
  • Recorded an end-to-end demo video of every animation against the live local stack, including the real Stripe test checkout for the activation and purchase stamps (shared in the session)

https://claude.ai/code/session_01DobvVEwfVg89UUMzUBsxRF

Summary by CodeRabbit

  • New Features

    • Added clearer activation success screens for DevPass purchases and redemptions, including animated confirmation overlays and transaction details.
    • Copy buttons now smoothly transition between copy and copied states.
    • Chat history collapse transitions now preserve accessibility and avoid unwanted animation during initial loading.
  • Improvements

    • Added polished entry animations across dashboard, census, credits, and points displays.
    • Animations now respect reduced-motion preferences.
    • Buttons provide subtle pressed-state feedback, and toast dismissal behavior is more consistent.
    • Improved popover animation positioning.

Implements the 10 gated opportunities from the animation audit:
press feedback on all shared buttons, popover transform-origin fix,
symmetric toast exits, DevPass activation + Reset Pass purchase visa
stamps, Lounge points odometer roll, copy-button crossfades, animated
Chats collapse, CREDITS ADDED stamp-in, and census page stagger.
All movement carries prefers-reduced-motion fallbacks.

Claude-Session: https://claude.ai/code/session_01DobvVEwfVg89UUMzUBsxRF
@coderabbitai

coderabbitai Bot commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR adds reduced-motion-aware animations and state transitions across dashboard, playground, census, and shared UI components. It updates activation and pass-success feedback, copy-button icons, chat-history collapse behavior, entrance animations, button press styling, popover origins, and toast dismissal transitions.

Changes

UI motion and feedback

Layer / File(s) Summary
Activation and pass success feedback
apps/code/src/app/dashboard/DashboardShell.tsx, apps/code/src/app/dashboard/components/ResetPassCard.tsx
Activation and reset-pass success states now use timed overlays, animated stamps, purchase amounts, and reduced-motion behavior.
Animated copy controls
apps/code/src/app/dashboard/components/QuickStart.tsx, apps/code/src/components/CodingModelsShowcase.tsx, apps/playground/src/components/ai-elements/code-block.tsx, apps/ui/src/lib/utils/markdown-code-block.tsx
Copy buttons keep both icons mounted and animate transitions between copy and completed states.
Playground status animations
apps/playground/src/components/credits/top-up-credits-dialog.tsx, apps/playground/src/components/lounge/sidebar-points.tsx
Credit-success, points, and streak displays now animate with reduced-motion fallbacks.
Hydrated chat-history transitions
apps/playground/src/components/playground/chat-sidebar.tsx
Chat history uses post-hydration grid and opacity transitions, with collapsed content marked aria-hidden and inert.
Page entrances and shared interaction styling
apps/code/src/app/data/[year]/page.tsx, apps/*/src/components/ui/button.tsx, apps/ui/src/lib/components/{toast.tsx,...}, apps/playground/src/components/ui/popover.tsx
Census content gains staggered entrances; shared buttons gain pressed scaling, while popover and toast transition classes are refined.

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

Possibly related PRs

Suggested reviewers: steebchen

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: motion polish across the UI, playground, and code areas.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/motion-polish

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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/code/src/app/dashboard/components/ResetPassCard.tsx (1)

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

Duplicate "stamp overlay" motion pattern across two files. Both blocks build the same double-border, uppercase stamp card with an identical reduceMotion-branched initial/animate shape and { type: "spring", duration: 0.4 } transition — differing only in message content, colors, and whether AnimatePresence/exit is used. This duplication means fixes (e.g. adding exit animation, or accessibility tweaks) have to be applied twice and can drift, as already evident in DashboardShell.tsx's block lacking the exit handling that ResetPassCard.tsx has.

  • apps/code/src/app/dashboard/components/ResetPassCard.tsx#L208-L251: extract this block's card/motion logic into a shared StampOverlay component (props: kind/color, title, subtitle, reduceMotion, optional exit).
  • apps/code/src/app/dashboard/DashboardShell.tsx#L519-L553: replace the inline motion.div stamp with the same shared StampOverlay component, passing the "DevPass activated" copy.
🤖 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 `@apps/code/src/app/dashboard/components/ResetPassCard.tsx` around lines 208 -
251, Extract the duplicated stamp-card motion and styling from ResetPassCard.tsx
lines 208-251 into a shared StampOverlay component accepting kind/color, title,
subtitle, reduceMotion, and optional exit props; preserve the existing
redeemed/purchase appearance and animation behavior. Replace the inline stamp
motion in DashboardShell.tsx lines 519-553 with StampOverlay, passing the
“DevPass activated” copy; both sites require changes.
🤖 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 `@apps/code/src/app/dashboard/components/ResetPassCard.tsx`:
- Around line 164-165: Replace the direct setStampOverlay/setTimeout pairs in
both redeem and purchase success handlers with a shared showStampOverlay helper
that clears the existing pending timeout before scheduling a new 2200ms
dismissal; update purchaseMutation.onSuccess to call showStampOverlay({ kind:
"purchased", amount: data.amount }) and preserve the corresponding redeemed
overlay payload.

---

Nitpick comments:
In `@apps/code/src/app/dashboard/components/ResetPassCard.tsx`:
- Around line 208-251: Extract the duplicated stamp-card motion and styling from
ResetPassCard.tsx lines 208-251 into a shared StampOverlay component accepting
kind/color, title, subtitle, reduceMotion, and optional exit props; preserve the
existing redeemed/purchase appearance and animation behavior. Replace the inline
stamp motion in DashboardShell.tsx lines 519-553 with StampOverlay, passing the
“DevPass activated” copy; both sites require changes.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7336fa40-7775-4859-b863-f55cd64f5a10

📥 Commits

Reviewing files that changed from the base of the PR and between a1abc8e and 0594707.

📒 Files selected for processing (16)
  • apps/code/src/app/dashboard/DashboardShell.tsx
  • apps/code/src/app/dashboard/components/QuickStart.tsx
  • apps/code/src/app/dashboard/components/ResetPassCard.tsx
  • apps/code/src/app/data/[year]/page.tsx
  • apps/code/src/components/CodingModelsShowcase.tsx
  • apps/code/src/components/ui/button.tsx
  • apps/playground/src/components/ai-elements/code-block.tsx
  • apps/playground/src/components/credits/top-up-credits-dialog.tsx
  • apps/playground/src/components/lounge/sidebar-points.tsx
  • apps/playground/src/components/playground/chat-sidebar.tsx
  • apps/playground/src/components/ui/button.tsx
  • apps/playground/src/components/ui/popover.tsx
  • apps/ui/src/lib/components/button.tsx
  • apps/ui/src/lib/components/toast.tsx
  • apps/ui/src/lib/utils/markdown-code-block.tsx
  • packages/shared/src/components/ui/button.tsx

Comment on lines +164 to +165
setStampOverlay({ kind: "redeemed" });
setTimeout(() => setStampOverlay(null), 2200);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Overlapping redeem/purchase actions can clear the overlay early.

Each onSuccess schedules an independent, untracked setTimeout(..., 2200). If a user redeems and then purchases (or vice versa) within 2200ms, the second overlay ("purchased") is shown, but the first timer still fires at its original 2200ms mark and clears stampOverlay prematurely — before the second overlay's own 2200ms has elapsed. A later, now-stale second timeout then fires as a no-op.

🐛 Proposed fix: track and clear the pending timeout
+	const stampTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
+
+	const showStampOverlay = (
+		overlay: NonNullable<typeof stampOverlay>,
+	) => {
+		if (stampTimeoutRef.current) {
+			clearTimeout(stampTimeoutRef.current);
+		}
+		setStampOverlay(overlay);
+		stampTimeoutRef.current = setTimeout(() => setStampOverlay(null), 2200);
+	};
+
+	useEffect(() => {
+		return () => {
+			if (stampTimeoutRef.current) {
+				clearTimeout(stampTimeoutRef.current);
+			}
+		};
+	}, []);
+
 	const redeemMutation = api.useMutation(
 		"post",
 		"/dev-plans/reset-pass/redeem",
 		{
 			onSuccess: async () => {
-				setStampOverlay({ kind: "redeemed" });
-				setTimeout(() => setStampOverlay(null), 2200);
+				showStampOverlay({ kind: "redeemed" });
 				await invalidateStatus();
 			},

Apply the analogous change to purchaseMutation.onSuccess, replacing its setStampOverlay/setTimeout pair with showStampOverlay({ kind: "purchased", amount: data.amount }).

Also applies to: 179-180, 208-233

🤖 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 `@apps/code/src/app/dashboard/components/ResetPassCard.tsx` around lines 164 -
165, Replace the direct setStampOverlay/setTimeout pairs in both redeem and
purchase success handlers with a shared showStampOverlay helper that clears the
existing pending timeout before scheduling a new 2200ms dismissal; update
purchaseMutation.onSuccess to call showStampOverlay({ kind: "purchased", amount:
data.amount }) and preserve the corresponding redeemed overlay payload.

@smakosh
smakosh added this pull request to the merge queue Jul 26, 2026
Merged via the queue into main with commit c01808c Jul 26, 2026
22 of 23 checks passed
@smakosh
smakosh deleted the feat/motion-polish branch July 26, 2026 16:27
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