Skip to content
Black FridayBlack Friday launch price: Lifetime $149 until 30 Nov. Regular price $299 from 1 Dec.ends in 15d 02:31:46Get Lifetime →
loopkit
proNew345 lines · framer-motion

Device Mockup Carousel

A coverflow of phones, every screen drawn live. A full-width Cards section showing a coverflow carousel of hand-drawn phone mockups. The active device is centered and large; neighbours peek in at reduced scale and opacity. Each screen is a distinct CSS/SVG composition — no screenshots, no logos.

Use it for
Showing a family of app screens, product surfaces or feature states side by side, when you don't have (or don't want) real screenshots.
Themes
Light + dark
License
Commercial use
Live

Cards

One shell, every surface

Every screen here is generated live. Swap the count, the pace, or let it drift on its own.

Signal

tsx
"use client";

import * as React from "react";
import { motion, useReducedMotion } from "framer-motion";
import { cn } from "@/lib/utils";

function useReducedMotionSafe() {
  const prefersReduced = useReducedMotion();
  const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => setMounted(true), []);
  return mounted ? !!prefersReduced : false;
}

/**
 * Full-width "Cards" section: a coverflow-style carousel of hand-drawn phone
 * mockups, each screen filled with a distinct, entirely generated CSS/SVG
 * composition (no photography, no app logos). The active device sits centered
 * and large; its neighbours peek in from the sides at reduced scale/opacity.
 */

export interface DeviceMockupCarouselProps {
  eyebrow?: string;

The rest is in Pro.

Full source, the rebuild prompt and registry install unlock with Pro or Lifetime.

Get Pro

How it behaves

  • →Phone chassis (rounded frame, notch, screen cut-out) is pure CSS; each screen's content is one of 4 generated layouts (stat tiles + sparkline, chat bubbles, album art + waveform, list rows) recoloured per slide from the design-system accent tokens.
  • →Slide offset from the active index is computed as a shortest signed distance around the loop, then mapped to a pixel translateX (measured via ResizeObserver on the stage, so it scales with container width), a scale (1 / 0.8 / 0.62) and an opacity (1 / 0.55 / 0.22) by distance.
  • →Framer Motion animates x/scale/opacity with a spring on every index change; useReducedMotion collapses that to a 0ms transition.
  • →On viewports under ~560px wide only the immediate neighbours are shown (the second ring is hidden) so nothing overflows the viewport; the stage itself is overflow-x-hidden.
  • →Autoplay advances one slide on an interval and is skipped entirely when prefers-reduced-motion is on; it also pauses for as long as the carousel region is hovered or contains focus, and the interval/listeners are cleared on unmount or when any of its inputs change.
  • →count slices the built-in slide list down to 4-6 cards; the active index wraps back into range if it shrinks.

Accessibility

  • ✓The carousel is a `role="region"` with `aria-roledescription="carousel"` and an `aria-label`; it is keyboard-focusable and ArrowLeft/ArrowRight navigate it from anywhere inside.
  • ✓Prev/Next are real `<button>`s with `aria-label`; dot indicators are buttons labelled `Go to slide N` with `aria-current="true"` on the active one.
  • ✓Only the centered, active phone is exposed to assistive tech; the partially visible neighbours are marked `aria-hidden` since their content duplicates slides reachable via Prev/Next.
  • ✓Honours prefers-reduced-motion.