addmotion
Submit Free API key

Pricing / offer promo — price drop + plan cards

The old price strikes through, the new price counts down into place, three plan cards fan in, and a deadline line closes.

Prompt

# Pricing / offer promo — price drop + plan cards

## Format (read first)
- 1080×1350 (4:5), 30fps, 7.0s = 210 frames
- Target: Single HTML file

## Brief
A vertical (4:5) offer promo (7s) for Ledgerly. Urgent but not cheap: no starbursts, no flashing. The price change is the hero.

## Look
- Palette (background, accent, text): #111111, #ffd23f, #ffffff
- Type: Heavy sans, tabular numerals for prices. Price 180px/900.

## Beats (exact timings)
1. 0.0–1.2s — "$24/mo" scales in at center (from 0.9, ease-out-back 6% overshoot).
2. 1.2–2.2s — A 10px accent-colored strike line draws across it left→right (300ms ease-in-out), then the old price drops 40px and fades to 30% opacity.
3. 2.2–3.6s — "$12/mo" rolls in like an odometer (each digit a vertical strip, rightmost spins most), ease-out-quart 1.1s, accent color.
4. 3.6–5.6s — Three plan cards "Starter", "Pro", "Team" fan in from below with 100ms stagger and a slight rotation (-4°, 0°, 4°) that settles to 0°; the middle card is 8% larger and accent-outlined.
5. 5.6–7.0s — "Ends Sunday at midnight." types in under the cards; "Ledgerly" logo at the bottom. Hold ≥ 0.8s.

## Motion rules
- Numbers use tabular figures so widths never jump.
- Only the new price uses the accent fill; everything else is neutral.

## Known failure modes — avoid these
- Odometer digits clipping at the top — give each digit strip 1.1em line box.
- Currency symbol spinning with digits — keep it static.

## Build
- Output ONE self-contained HTML file. No CDNs, web fonts, images or scripts from URLs.
- The stage is exactly 1080×1350 and scales to fit the window (letterbox) while keeping the aspect ratio.
- Expose window.__addmotion = { width: 1080, height: 1350, fps: 30, duration: 7, seek(t) } where seek(t) renders the exact frame for time t in seconds.
- Make every frame a pure function of t: compute positions from t (with easing functions you define) rather than accumulating state. Use requestAnimationFrame only to call seek(performance.now()/1000 % duration) for live preview.
- If you use CSS @keyframes, seek(t) must set animation-play-state: paused and a negative animation-delay of -t seconds on every animated element.
- To export MP4, step seek(t) frame by frame in a headless browser, screenshot each frame, and encode with ffmpeg.

## Done when
- [ ] Old → new price change is readable in one glance
- [ ] Deadline readable for ≥ 0.8s
- [ ] You scrubbed the start, middle and end of every beat and nothing overlaps, clips or jumps

Before writing code, restate the beat list with frame numbers. Then build it in one pass.

More like this

16:9

SaaS feature promo — cursor walkthrough

Ads & promos · addmotion studio
16:9

Odometer counter

Data & charts · Dataframe (demo)
16:9

Infinite marquee ticker

Kinetic type · addmotion studio
1:1

App launch — phone mock + store buttons

Launch videos · addmotion studio
Pricing / offer promo — price drop + plan cards · addmotion