---
title: "BRAND Duolingo 2026 · Recipe: anytime-scroll-scene"
url: https://memocore.ai/memos/6abe2d7b57d33af4d524764f
project: "Brand Styles"
tags: "brand-duolingo"
updated_at: "2026-10-01T10:12:23.589Z"
---

# BRAND Duolingo 2026 · Recipe: anytime-scroll-scene

HEADER
brand: Duolingo; design_date: 2026-10; kind: scene; used_in: Page: home S3 (background fade), S4 (scene), S1 (topbar hiding)
evidence: measured from the splash module of the app bundle (scroll handlers, spring hook, class map), its CSS module and the Lottie files lottie/splash/c16e90b9... (foreground) and c02b5f75... (background), plus live screenshots on https://www.duolingo.com/ 2026-10-01 unless marked

LOOK
While you scroll from the feature rows into "learn anytime, anywhere", the white page softly turns pale sky blue (#ddf4ff), the fixed topbar slides away, and a wide field of floating 3D-ish phones, letter tiles (ñ, 中, ア), gems, crowns and flames drifts across the whole width. The phones' motion is tied to the scroll: scrolling down moves them forward, scrolling back rewinds them, always with a soft spring lag. Background objects keep a gentle idle loop.

STRUCTURE
backgrounds wrapper (position relative) containing: (1) an absolutely positioned full-size layer with background #ddf4ff, opacity 0, z-index -1 (the fade layer); (2) S3 feature rows; (3) S4 section (flex center, min-height 100vh, overflow hidden) -> inner column (max 1728px, padding 140px 0 96px) -> text block (title, badges, z-index 1) -> scene box (display grid, margin-top -340px, margin-left -220px) holding three stacked layers in the same grid cell: static SVG placeholder, background Lottie (looping), foreground Lottie (scroll-scrubbed), plus an invisible probe strip (absolute, top 26%, bottom 30%, full width) used to measure scroll progress

KEY PARAMETERS
scene: 4100:2300 aspect, width 2000px (>=1080), 1600px (768-1079), 1200px (<768); margin-top -340 / -200 / -90px; margin-left -220 / -180 / -120px; pointer-events none
foreground Lottie: 4100x2300, 30fps, frames 0-450 (451 total), never autoplays; frame = clamp(map(probeTop, viewportBottom -> -probeHeight, 0 -> 450), 0, 450), smoothed by a spring (stiffness 170, damping 26, mass 1, restDistance 0.5, restSpeed 2, clamped) and applied with goToAndStop(frame)
background Lottie: 4100x2300, 30fps, timeline 250-560, loops continuously while this scene is the one nearest the viewport center (otherwise paused)
fade layer: opacity = spring(map(S4 top, viewport bottom -> viewport top, 0 -> 100) clamped) / 100; so the blue starts when the S4 top enters the bottom of the viewport and is full when it reaches the top; it covers the whole wrapper, so the last feature rows turn blue too
topbar: hidden (translateY(-100%), transition transform 400ms cubic-bezier(0.22,1,0.36,1)) while S4 top - 96px is above the viewport top AND the bottom of the following Super band (S5) is still below the viewport top; shown again after S5 scrolls away
title: Feather 64px #042c60 lowercase, two app badges below, both above the scene (z-index 1)

MOTION
at S4 top = viewport bottom: fade 0, phones frame 0 (phones low/at rest)
at S4 top = mid viewport: fade ~0.5, phones about a third of the way
at S4 top = viewport top: fade 1 (pale blue), topbar slides up
while the probe strip travels from the viewport bottom to just above the viewport top: phones play frames 0 -> 450 in step with the scroll, lagging by the spring (~0.3-0.5s to settle (est))
scroll back: everything reverses through the same spring (fade back to white, phones rewind, topbar returns)

SCENE
renderer: lottie-web SVG renderer, two animations stacked in one grid cell
camera: flat 2D, no perspective; objects drawn in a pseudo-3D isometric style
objects: 5-6 smartphones with dark navy frames and light-blue flat screens, colored letter tiles (purple ñ, pink 中, green ア), blue gems, a gold crown, an orange flame, small hexagon confetti
background: transparent over the #ddf4ff fade layer
post effects: none
interaction: scroll only (no pointer reaction)
mobile: same scene at 1200px wide, cropped by overflow hidden

STATES
reduced motion: no Lottie is loaded; only the static SVG placeholder (first frame) is shown; the fade and the topbar hiding still work
loading: placeholder visible until the first frame of a Lottie renders, then hidden
touch: same, driven by native scroll

HOW TO BUILD
Wrap the feature rows and the download band in one relative container with an absolute #ddf4ff layer at opacity 0 behind them. On scroll, compute the band's progress (top from viewport bottom to viewport top) and the scene probe's progress, feed both into a critically damped spring (stiffness 170, damping 26) per value, and write the results to the layer opacity and to a Lottie (or a canvas image sequence) via goToAndStop. Hide the fixed topbar with translateY(-100%) while the band is at the top. Simpler fallback: a CSS scroll-driven animation (animation-timeline: view()) on the layer opacity and a parallax translate of a static illustration.

PITFALLS
the background must fade, not switch: no hard edge between white and blue; the scene must be much wider than the viewport (2000px at 1440) and offset up and left so objects bleed past both edges and behind the title; the phone motion must be scrubbed (reversible), not autoplayed; without the spring the motion looks jittery; keep the title navy #042c60, not green

SCREENSHOTS
- file: duolingo_2026_anytime-scroll_d1440_p1.jpg
  shows: entering: last feature row with the blue layer at ~0.4 opacity, title arriving, topbar still visible
- file: duolingo_2026_anytime-scroll_d1440_p2.jpg
  shows: band at the top: full #ddf4ff, topbar hidden, title, app badges and the phone field mid-way
- file: duolingo_2026_anytime-scroll_d1440_p3.jpg
  shows: leaving: phones near the end of their timeline, navy Super band entering at the bottom, topbar still hidden
