| name | conveyor-pan |
| description | motion-graphic primitive — continuous lateral card scroll at constant velocity. multiple cards visible simultaneously (e.g. 2.3 cards at once for partial-card peek at canvas edges, implying infinite content). distinct from card-stagger-slide which is discrete-stagger reveal. central to SP-E chaos-card style and to phone-card-carousel archetype (A9). cards translate linearly — never accelerate/decelerate. |
conveyor-pan
Purpose
Implement a horizontally-scrolling card carousel where cards translate continuously at constant velocity, with partial cards visible at the canvas edges to imply infinite content. The conveyor IS the transition — there's no scene cut.
Params (params.schema.json)
{
"id": "uturn-conveyor",
"cards": [],
"card_width_px": 720,
"card_height_px": 1280,
"card_gap_px": 80,
"card_radius_px": 32,
"card_tilt_deg": 0,
"velocity_px_per_sec": 360,
"direction": "right-to-left",
"easing": "linear",
"start_offset_px": 0,
"loop": false,
"cards_visible_at_once": 2.3
}
Each card in cards[]:
{
"bg_color": "#FF5A21",
"tilt_deg": -5,
"content": { }
}
Behaviour
- Render a horizontal flex strip with all cards laid out.
- Compute
stripX = -velocity_px_per_sec * frame / fps + start_offset_px.
- Apply
transform: translateX(stripX) to the strip.
- Each card has its own tilt baked in via
transform: rotate(card_tilt_deg).
- Apply a CSS
overflow: hidden mask on the parent so partial cards clip cleanly at the canvas edges.
Implementation: a Remotion component using useCurrentFrame() and direct transform: translateX (no spring; linear motion).
Style pack overrides
SP-E (chaos-card)
card_tilt_deg: random per card, range -8° to +8°, seeded.
velocity_px_per_sec: 360 (default).
- Cards have sticker-chip-pop overlays that pop in 8 frames after each card enters the visible window.
- Music beat anchor: not required (conveyor is continuous).
SP-A — not used (Marshmallow uses card-stagger-slide + step-pan).
SP-D — not used (Magazine uses scrolling-index-dual-rail, which is vertical).
When to use
- Phone-card-carousel archetype (A9).
- "Feed-scrolling" UI mocks where the user is showing a continuously-scrolling app feed.
- Any spot where the carousel rhythm IS the transition (no scene cuts within the carousel).
When NOT to use
- Discrete pricing carousels (use
card-stagger-slide + step-pan instead — see A4).
- When the user wants to dwell on each card (conveyor is constant velocity; use step-pan for dwells).
- In SP-A/B/C/D/F/G — pack-incompatible.
Quality Checks
- Velocity is constant (no easing on translateX).
- Partial cards at edges clip cleanly (no white gap, no overflow).
- Card tilts are visible but moderate (±5–8° max).
- Cards don't accelerate at scene start or decelerate at scene end.
- Strip total width allows the conveyor to run for the full scene duration without exposing the strip's leftmost or rightmost edge.
Failure Modes
- Conveyor accelerates at start. Easing is not linear — verify
easing: linear and no spring config.
- Strip end exposes white canvas.
cards_visible_at_once × card_width + card_gap × scene_duration > strip total width. Add more cards (or duplicate cards if loop=true).
- Cards visibly snap into place.
velocity_px_per_sec is too low — bump to 300+ for noticeable continuous motion.
- Cards visibly blur from too-fast motion. Velocity too high (> 600 px/s on 1080w canvas). Lower to 300-450.