WebberUI

Paste-Up Assembly

Blocks scattered like paste-up cuttings that fly back into their grid slots with FLIP as you scroll in, and scatter apart again when you scroll back.

This is a WebberUI Pro component

Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.

How to install Pro components →See the plans →

Loading preview…
npx shadcn@latest add "https://webberui.com/r/paste-up-assembly.json?t=<install token>"

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

2
64
12
0.5
7
<PasteUpAssembly />

Installation

npx shadcn@latest add "https://webberui.com/r/paste-up-assembly.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/paste-up-assembly.

Usage

Every direct child becomes one "cutting". At the start each block is randomly offset, rotated, and stacked, like sheets scattered across a work table; once the layout scrolls into the pinned range, all the elements fly back into their own grid slots in sequence and assemble a clean layout. Scrolling back scatters them again.

import { PasteUpAssembly } from "@/components/ui/paste-up-assembly";

<PasteUpAssembly columns={3} gap={16}>
  <div>Cutting A</div>
  <div>Cutting B</div>
  <div>Cutting C</div>
  <div>Cutting D</div>
  <div>Cutting E</div>
  <div>Cutting F</div>
</PasteUpAssembly>;

If the scrolling happens inside a nested overflow container, pass that container's ref to container:

const scrollerRef = React.useRef<HTMLDivElement>(null);

<div ref={scrollerRef} className="h-[300px] overflow-y-auto">
  <PasteUpAssembly container={scrollerRef} stickyTop={12} travel={340}>
    {/* ... */}
  </PasteUpAssembly>
</div>;

Props

PropTypeDefaultDescription
childrenReact.ReactNodeEvery direct child becomes one cutting
columnsnumber3Number of grid columns
gapnumber16Grid gap (px)
scatternumber96Scatter radius (px); larger scatters wider and stacks messier
rotatenumber10Maximum rotation while scattered (deg)
scaleFromnumber0.9Scale to start from while scattered (0–1)
staggernumber0.5How much each piece's assembly time window is offset (0 lands all at once, 1 fully in sequence)
travelnumber600Scrollable distance while pinned (px)
stickyTopnumber0Distance from the top of the scroll container when the layout pins (px)
decoration"tape" | "pin" | "none""tape"Decoration style on each cutting
seednumber1Scatter random seed; change it for a different scatter layout (SSR-stable)
containerReact.RefObject<HTMLElement | null>Nested scroll container ref; defaults to the window as the scroll container
classNamestringApplied to the outermost container
itemClassNamestringApplied to each cutting's outer element (which carries the transform)

How it works

  • The assembly is driven by scroll progress (scrubbed) rather than played once, so blocks gather and scatter reversibly as you scroll back and forth.
  • The grid provides each cutting's final position (the Last), and the scattered state is just a transform offset relative to that slot (the invert) — so the FLIP effect is achieved without measuring the DOM at all.
  • The scatter layout is generated from seed with a deterministic random function, so the server and client output match and there is no hydration gap; change the seed for a brand new scatter arrangement.
  • Each piece's assembly time window is concentrated in the middle of the pinned range and offset by stagger, which reads like sheets being pasted back onto the layout one at a time.
  • travel sets the scroll distance while pinned; inside a nested container, lower travel to match the shorter scroll height.

Accessibility

  • When the user has "reduce motion" enabled at the system level (prefers-reduced-motion), the clean aligned grid is rendered directly, with no scattering and no pinned scrolling.
  • Content stays in its natural DOM order — the scattering is only a visual transform and does not affect reading order or Tab order.
  • Decorations such as tape and pins are marked aria-hidden with pointer events disabled, so they do not interfere with interaction or assistive technology.

On this page