# ContainerScroll

> A hero block where a device-like frame starts tilted back in 3D and straightens as the page scrolls, with the title drifting up.

## Facts

- **Product**: Crew OS
- **Family**: Motion
- **Global**: `window.DigitalCrew.ContainerScroll`
- **Source**: `digitalcrew-orchestrator: components/ui/container-scroll-animation.tsx`
- **Import in the app**: `import { ContainerScroll } from "@/components/ui/container-scroll-animation";`
- **Live preview**: /design/components/container-scroll/preview.html
- **Page**: /design/components/container-scroll

## Guidelines

**Use it for** one product showcase per landing page: a screenshot, video or live mock of the workspace under a headline. Crew OS uses it for the scrolling product video.

**What you provide**: `titleComponent` (your heading and subtitle) and `children` (what shows on the screen; it fills the frame). Nothing else is configurable.

**Anatomy**: the outer block is 960px tall (`h-[60rem]`), 8px padding (80px from `md`), with `perspective: 1000px`. The frame is `max-w-5xl`, 480px tall (640px from `md`), `rounded-[30px]`, a 4px `#6C6C6C` border, `bg-[#222222]`, 8px padding (24px from `md`) and a six-layer drop shadow; it overlaps the title by 48px. The screen inside is `rounded-2xl`, `bg-gray-100` (`dark:bg-zinc-900`), 16px padding from `md`.

**Behaviour**: progress is the block's position in the window scroll (Framer Motion `useScroll`). Across it the frame rotates on X from 20° to 0°, scales from 1.05 to 1 (0.7 to 0.9 at 768px wide and below) and the title moves up 100px. Only window scroll drives it, so it cannot live inside a scrolling panel; this preview makes the card itself scrollable. It does not check reduced motion.

**Don't** use it twice on a page, put interactive forms on the tilted screen, or rely on text inside the frame being readable before it flattens.

## API

```ts
export declare const ContainerScroll: ({ titleComponent, children, }: {
    titleComponent: string | React.ReactNode;
    children: React.ReactNode;
}) => any;
export declare const Header: ({ translate, titleComponent }: {
    translate: MotionValue<number>;
    titleComponent: React.ReactNode;
}) => any;
export declare const Card: ({ rotate, scale, children, }: {
    rotate: MotionValue<number>;
    scale: MotionValue<number>;
    translate: MotionValue<number>;
    children: React.ReactNode;
}) => any;
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  var rows = [
    ["Claire Dubois", "CFO, Northwind Traders", "Meeting booked", "Tue 14:30"],
    ["Omar Haddad", "VP Finance, Brightline", "Replied", "18 min ago"],
    ["Lena Fischer", "Head of Sales, Kestrel Labs", "Opened 3×", "1 h ago"],
    ["Marc Lefèvre", "Founder, Atlas Freight", "Connected", "3 h ago"],
    ["Aiko Tanaka", "COO, Vantage Health", "In sequence", "Step 2 of 4"]
  ];
  function Screen() {
    return h("div", { className: "grid h-full content-start gap-4 bg-background p-4 text-foreground" },
      h("div", { className: "flex items-center justify-between" },
        h("div", null, h("p", { className: "text-lg font-semibold" }, "Good morning, Julie"), h("p", { className: "text-muted-foreground text-sm" }, "Max worked through 214 prospects overnight.")),
        h(DC.Button, null, h(I.Sparkles), "Ask Max")),
      h("div", { className: "grid grid-cols-3 gap-3" },
        [["Meetings booked", "11"], ["Reply rate", "8.9%"], ["Pipeline added", "€184k"]].map(function (k) {
          return h("div", { key: k[0], className: "rounded-xl border bg-card p-4" }, h("p", { className: "text-muted-foreground text-xs" }, k[0]), h("p", { className: "text-2xl font-semibold tabular-nums" }, k[1]));
        })),
      h("div", { className: "divide-y rounded-xl border bg-card" }, rows.map(function (r) {
        return h("div", { key: r[0], className: "flex items-center gap-3 px-4 py-3 text-sm" },
          h("span", { className: "bg-muted flex size-8 items-center justify-center rounded-full text-xs font-medium" }, r[0].split(" ").map(function (w) { return w[0]; }).join("")),
          h("span", { className: "flex-1" }, h("span", { className: "font-medium" }, r[0]), h("span", { className: "text-muted-foreground" }, " · " + r[1])),
          h(DC.Badge, { variant: "secondary" }, r[2]),
          h("span", { className: "text-muted-foreground w-24 text-right text-xs" }, r[3]));
      })));
  }
  function App() {
    return h("div", null,
      h(DC.ContainerScroll, { titleComponent: h("div", { className: "mb-8 text-center" },
        h("h2", { className: "mb-3 text-4xl font-bold" }, "Your sales floor, on autopilot"),
        h("p", { className: "text-muted-foreground mx-auto max-w-lg" }, "Digital Workers prospect, follow up and book meetings while you sleep.")) },
        h(Screen)),
      h("div", { className: "text-muted-foreground flex h-[560px] items-start justify-center text-sm" }, "Scroll back up to tilt the screen again."));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Motion

- [ActionFocusSession](/design/components/action-focus-session.md): The focus timebox for one task in the actions cockpit: a live billable clock with approve, start, pause, run and done, and a burst of sparkles on completion.
- [CardResize](/design/components/card-resize.md): A container that tweens its width and height when its content changes (`.t-resize`).
- [ChapterScrubber](/design/components/chapter-scrubber.md): A rail of ticks, one per chapter, that swell like a dock under the pointer, with a card previewing the hovered chapter.
- [FeatureSlideshow](/design/components/feature-slideshow.md): A step-by-step feature explainer: an accordion of steps on the left that advances on a timer, a progress line on the open step, and a large media slot on the right.
- [FirstBentoAnimation](/design/components/first-bento-animation.md): A self-playing chat vignette for the bento grid: a user asks for a meeting slot, the Digital Crew avatar shows typing dots, then the reply streams in as a `Reasoning` block.
- [FourthBentoAnimation](/design/components/fourth-bento-animation.md): A scheduling vignette for the bento grid: a week ruler, three task bars that spring into place, and a time cursor that follows the pointer.
- [HyperText](/design/components/hyper-text.md): A monospaced, uppercase text effect: letters scramble through random characters, then lock in from left to right.
- [InfiniteSlider](/design/components/infinite-slider.md): A JavaScript-driven endless strip (Framer Motion) that renders its children twice and slides them in a loop, optionally slowing on hover.
- [JoyfulTaskCheckbox](/design/components/joyful-task-checkbox.md): A task checkbox with a small, restrained completion moment: one soft bloom, two sparks, then stillness.
- [Lottie](/design/components/lottie.md): The lottie-react player, exported as-is, for the Lottie animations that ship with Crew OS (`animations/*.json`).
- [Marquee](/design/components/marquee.md): An endless CSS scroll of repeated content, horizontal or vertical, speed set with two CSS variables.
- [MotionScale](/design/components/motion-scale.md): The shared motion scale made visible: the same distance travelled on each duration token and each easing, with a Replay button.
- [NumberFlowCounter](/design/components/number-flow-counter.md): A small dark pill that shows one number at a time and rolls its digits to the next value every two seconds (NumberFlow).
- [OrbitingCircles](/design/components/orbiting-circles.md): Places its children on a circular orbit around the centre of the parent and spins them, with an optional faint ring for the path.
- [ShimmerText](/design/components/shimmer-text.md): A status line with a light band sweeping across its glyphs — Max's "Thinking…" and live tool lines (`.t-shimmer`).
- [SignatureGradient](/design/components/signature-gradient.md): The signature Digital Crew gradient — indigo → pink → amber (`dc-andre`, `dc-camille`, `dc-amber`) — in its four forms.
- [SkeletonReveal](/design/components/skeleton-reveal.md): A skeleton that cross-blurs into the loaded content, so the swap reads as one motion (`.t-skel`).
- [StreamingText](/design/components/streaming-text.md): Streamed words resolving through a soft cross-blur, one after another (`.t-stream-w` → `.is-in`).
- [ThirdBentoAnimation](/design/components/third-bento-animation.md): An insight vignette for the bento grid: a smooth area line draws itself, a dot pulses at its midpoint and a dark pill above it ticks through values.
- [UniboxMotion](/design/components/unibox-motion.md): The Unibox's shared motion vocabulary: every surface moves on the same few springs, so the whole inbox feels like one physical material.
