AI CSS Animations

Three Phone App Promo

Three original phones in sage, oat and clay float staggered in 3D on a blush backdrop, each running a different screen of a plant-care app (a care list, a plant's history, a leaf scanner) while callouts name each feature.

Written and rendered by AI CSS Animations Oct 19, 2026

Type
prompt
Made with
Claude Opus 5.5 in Claude Code
Built in
three.js
Topics
SaaS promo · Phone · 3D · Product UI
What Claude made from the prompt below in Claude Code: one HTML file rendered frame by frame to video. Silent preview.

About this style

The three-phone layout is a long-running staple of mobile app marketing, seen in app store screenshots, landing-page heroes and launch videos: three devices side by side or staggered in depth, each showing a different screen. One image can then show the breadth of an app, a home screen, a detail view and a key action, while the staggered perspective adds depth and makes the app feel like a physical product. In motion, the phones usually drift or orbit slowly while their screens scroll and short callouts name each feature. It works when the three screens are real, readable and clearly different, the devices are lit like objects with soft shadows, and the camera moves slowly enough to read every label.

The prompt

Make a 10-second mobile app promo with three original phones staggered in 3D on a soft blush backdrop: each phone runs a different live screen of a plant-care app (a daily care list that scrolls, a plant's detail page where a watering is logged, a scanner that identifies a leaf), callouts with leader lines name each feature, and the camera drifts slowly around them.

<inputs>
If I don't give you something, use the default and don't ask.
- App: Mossback (fictional), a plant-care app. User: Sam.
- Left phone, "Today": "Good morning, Sam" · "3 plants need you today" · cards: Gus · Monstera · "Water 400 ml"; Ivy · Pothos · "Mist the leaves"; Frank · Fiddle leaf fig · "Turn toward the window"; then a "This week" strip (Mon–Sun with dots on Tue, Thu, Sat) and two more cards: Olive · Rubber plant · "Wipe the leaves"; Pip · Peperomia · "Check the soil".
- Center phone, plant detail: "Gus" · "Monstera deliciosa" · Light "Bright, indirect" · Water "Every 7 days · next Thu" · Humidity "58%" with a 7-day line (52, 55, 54, 57, 60, 59, 58) · button "Mark as watered" → "Watered today · next on Oct 28".
- Right phone, scanner: viewfinder on a leaf, then a result card: "Calathea orbifolia" · "96% match" · "Likes shade and high humidity".
- Callouts: "Daily care list" (left), "Every plant's history" (center), "Identify any plant" (right).
- Headline: "Keep every plant alive." Sign-off: Mossback wordmark · "Free to download".
- Length: 10 seconds.
</inputs>

<direction>
- Look: a bright, soft studio product shot that happens to move. Three matte phones in muted botanical colors float in a staggered arc on a blush cyclorama, lit like real objects: a broad soft key, a warm fill, a crisp rim along their edges, gentle contact shadows below. The screens are sharp and fully lit. Calm, premium, a little playful.
- Palette. Backdrop: blush #F2DCD3 at the top fading to #EBCBBE at the floor line, with a soft brighter center (#F7E7DF) behind the phones. Phone bodies: sage #9BB59A (left), oat #EFE4D2 (center), clay #D58A68 (right), each with a slightly darker band color on its side frame. Front glass #0C0D0E. Headline and leader lines: ink #2F3A2E. Callout pills #FFFFFF with ink text and a 8px moss dot. App: background #FAF7F1, cards #FFFFFF, hairlines #E9E4DA, ink #22301F, secondary #6B7566, moss accent #4E7A4A (buttons, active states), leaf greens #3F6B3A / #5E8F55 / #8DB27A, water blue #5B9BC8 (only for the droplet and the watering state). No neon, no purple, no gradients inside the app except the plant illustrations' gentle leaf shading.
- The phones: original devices, not any real model. Each body is a rounded box 1.5 × 3.2 × 0.16 units with a 0.22 corner radius and a 0.04 edge bevel; the front is a black glass inset 0.03 from the edges; the screen is a rounded rectangle inset 0.07 (the bezel) with a 0.17 corner radius and a single small round camera dot centered 0.11 from the top. No notches, islands or buttons copied from real phones; one short, flush side button on the right edge only.
- Placement (world units, y up): left phone at (−2.35, −0.05, −0.9), turned 18° toward the center around y and tipped back 5°; center phone at (0, 0.12, 0.35), turned −4°, tipped back 4°; right phone at (2.35, −0.15, −0.75), turned −17°, tipped back 6°. Each bobs ±0.04 on a 3.2 s sine with a different phase and rotates ±0.6° in sympathy.
- Camera: perspective, 30° vertical field of view, looking at (0, 0.05, 0). It starts at azimuth −9°, elevation 4°, distance 10.4 and travels to azimuth +6°, elevation 6°, distance 9.4 between 0.0 and 8.6 s on easeInOutSine, then stops. The three phones and their callouts fill the frame between x 300 and 1620 and y 210 and 1000 throughout.
- Lighting, so nothing comes out underlit: renderer with ACESFilmic tone mapping at exposure 1.15 and sRGB output; a hemisphere light (sky #FFF6EE, ground #E9C9BC, intensity 1.6); a key directional light #FFFFFF at 2.2 from (4, 6, 8); a warm fill #FFE9DF at 0.8 from (−6, 2, 4); a rim light #FFFFFF at 1.4 from (0, 4, −6) that draws a bright line along each phone's top and side edges; and a room environment map (RoomEnvironment through PMREMGenerator) at intensity 0.6 for soft reflections on the glass and frames. Bodies are MeshPhysicalMaterial with roughness 0.45 and clearcoat 0.3; the glass has roughness 0.05 and shows a faint, moving reflection band as the camera orbits. Screens use an unlit material with tone mapping off, so they show their true colors at full brightness.
- Shadows: no shadow maps. Under each phone, a soft contact shadow drawn as a radial gradient (rgba(90,50,40,0.26) at its center to transparent) on a horizontal plane at y −1.95, stretched 1.9 × 0.6 units and offset slightly away from the key light; it shrinks and lightens as its phone bobs up. No hard edges, no grey slabs.
- Screens: each is a 2D canvas, 780×1688 (a 390×844 layout at 2×), redrawn every frame and uploaded as a texture with anisotropic filtering at the renderer's maximum. App type in Urbanist 400 / 600 / 700: titles 28px, card titles 17px 600, details 14px, all in layout pixels. Each screen has a status row (time 8:12, a battery glyph) and a home bar.
- Left screen: "Good morning, Sam" in 28px 700, "3 plants need you today" in 15px secondary, then cards 358×88 with a 56px circular plant illustration (drawn leaves in the three greens), the name in 17px 600, the species in 13px secondary and the task as a moss chip. The list scrolls upward continuously by 420 layout px between 1.5 and 7.5 s on easeInOutSine, revealing the "This week" strip and the two extra cards; the first card's check ticks at 2.6 s.
- Center screen: a 390×300 hero illustration of Gus (an original monstera: five broad heart-shaped leaves with split edges and oval holes, built from bezier shapes in the three greens on a pale #EEF2E6 circle, in a clay pot), the name "Gus" in 30px 700 and the species in 15px italic secondary, three stat rows with small line icons, a humidity card with the 7-day line in moss and its last point marked, and a full-width "Mark as watered" button (moss, white 17px 600). At 4.6 s a tap ring appears on the button; a water droplet icon fills blue from the bottom in 0.4 s, and the button becomes a #E6F0F7 bar reading "Watered today · next on Oct 28" in #2F6E99, while the Water row updates to "Every 7 days · next Oct 28".
- Right screen: a viewfinder: a dark #1E241D frame with a large drawn calathea leaf (an oval leaf with pale silver-green stripes along its veins), four white corner brackets, and a thin moss scanning line that sweeps down once (1.8–3.0 s, easeInOutSine). At 3.1 s a result card slides up from the bottom (0.35 s, easeOutCubic): "Calathea orbifolia" in 20px 700, a "96% match" moss chip, "Likes shade and high humidity" in 14px, and a "Save to my plants" button.
- Callouts: DOM elements over the canvas, each anchored to a 3D point beside its phone's screen (projected every frame): a 1.5px ink leader line at 60% from a 6px ink dot on the phone's edge to a white pill (radius 20, padding 10px 18px, shadow 0 8px 20px rgba(60,30,20,0.12)) with a moss dot and the label in Urbanist 600 20px. Left pill sits at the upper left of the left phone, center pill below-right of the center phone, right pill at the upper right of the right phone; none overlaps a screen.
- Headline: "Keep every plant alive." in Gloock 400, 64px, ink, centered at y 120. Sign-off at the end: the Mossback wordmark (an original mark, a single rounded leaf with a center vein in moss, then "Mossback" in Urbanist 700 34px) and "Free to download" in Urbanist 500 20px secondary, centered at y 1030.
- Premium: phones that read as solid objects with real edge highlights and soft contact shadows, three genuinely different, live screens, a slow camera, legible callouts that never collide. Cheap: dark, murky lighting; plastic-looking flat shading; phones spinning; screens with blurry text; floating particles or leaves; a hard grey floor shadow; real phone silhouettes.
- Banned: real company names, logos and UI copied from existing products; real phone models' notches, islands, camera bumps or button layouts; app store badges or platform names; spinning devices; particles; lens flares; photo textures; anything flashing more than 3 times per second.
</direction>

<structure>
- 0.0–1.2s: the backdrop fades up from #F2DCD3; the phones rise into place from 1.2 units below with their final angles, left, center, right, 0.12 s apart, each on easeOutCubic over 0.8 s, their contact shadows fading in beneath; the screens show their first states.
- 1.0–1.6s: the headline rises 14px and fades in.
- 1.5–3.5s: the screens come alive: the left list starts scrolling, the first card ticks at 2.6 s; the scanner line sweeps (1.8–3.0 s) and the result card slides up (3.1 s).
- 2.2–3.8s: callouts arrive one by one: left (2.2 s), center (2.8 s), right (3.4 s); each leader line draws out from its dot in 0.3 s, then its pill fades in and settles 6px.
- 4.6–5.2s: on the center phone, the tap and the watering: the droplet fills and the button turns to "Watered today · next on Oct 28".
- 5.6–6.3s: the 6.0 s frame is the hero: the headline, three lit phones in their staggered arc with soft shadows, all three screens readable in their finished states (the list part-scrolled, Gus watered, the calathea identified) and all three callouts.
- 6.3–8.6s: the camera completes its drift and stops at 8.6 s; the left list finishes scrolling at 7.5 s; the sign-off fades in and rises at y 1030 (7.6–8.0 s).
- 8.6–10.0s: hold: the camera is still and the bob eases to rest by 9.0 s, so 9.0–10.0 s is a perfectly still frame.
For other lengths, stretch the camera drift and the list scroll, keep the screen events in order and at least 1 s of hold.
</structure>

<build>
- One self-contained index.html (inline CSS and JS), a 1920×1080 (16:9) stage scaled to fit the window, designed for 60fps. No image, video, texture or model files: the phone bodies are built from geometry, and the screens, shadows and backdrop gradient are canvases drawn in code.
- three.js pinned through an importmap from jsDelivr: "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js" and "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/" (RoundedBoxGeometry and RoomEnvironment come from addons). WebGLRenderer with antialias, preserveDrawingBuffer: true, setPixelRatio(devicePixelRatio), sized from the stage; render once inside seek.
- window.seek(t), t in seconds, computes every visual from t alone: camera, phone transforms, bob, screens, callout positions and every UI state are pure functions of t. No CSS transitions or CSS animations, no setTimeout/setInterval, no state carried between frames, randomness only from a seeded PRNG. Past the end, seek clamps to the last frame.
- Without ?render in the URL, drive seek from requestAnimationFrame so it plays in a browser (loop after a 1s end hold); with ?render, don't start that loop.
- Google Fonts via <link> are fine; await document.fonts.load() for each face and weight before defining window.seek, because the screen canvases draw text.
- Each frame: redraw the three screen canvases for t, set texture.needsUpdate, update the camera and phones, render, then project each callout anchor with the camera and place its DOM pill and SVG leader line in stage pixels.
</build>

<check>
Before showing me, step through one frame per second (t = 0…10): screenshot each and look at it. Fix overlaps, clipped or cramped text, and anything off-style or Banned. Check that the phones are well lit with visible rim highlights and no murky or near-black sides, the screens are sharp and fully bright, the contact shadows are soft (no grey slabs), no callout overlaps a screen or another callout, the screens are three different views, and the phones look like no real model. At 1.0 s all three phones are in place; at 3.5 s the scanner result is up and two callouts are in; the 6.0 s frame shows the headline, three phones, three finished screens and three callouts; the final frame adds the sign-off with the camera at rest. Confirm seek(10) and seek(11) match, so the final frame holds.
</check>

Ours, and free to use under CC0: copy it, change it, ship it. No credit needed.

Similar prompts

More like this on the motion design inspiration board: 3D motion design inspirationUI animation inspirationSaaS video inspirationApp animation inspiration