# Mobile App Landing

> A one-page site for a mobile app with a real 3D phone that turns to a new screen as you scroll through four features, plus store buttons, pricing with a monthly and yearly toggle, an FAQ and a QR download block. Built to be adapted in an afternoon: suits consumer apps, SaaS products, fintech, fitness, education and any launch that needs a phone in the hero.

Canonical: https://gsapvault.com/templates/mobile-app-landing-template
Live demo: https://gsapvault.com/demos/mobile-app-landing-template/index.html

| Property | Value |
|----------|-------|
| Type | template |
| Tier | paid |
| Price | £20 |
| Difficulty | advanced |
| Plugins | ScrollTrigger, SplitText |
| Techniques | webgl-shader, pinning, scrub, split-text, count-up, accordion, pointer-tilt, procedural-3d, keyboard-navigation, form-animation |
| Uses Lenis | Yes |

## Lighthouse, as measured

Google Lighthouse on the demo, 29 September 2026. A measurement of the demo as shipped, not a promise for your page.

| Category | Score |
|----------|-------|
| Accessibility | 100 |
| Best practices | 100 |

No performance score is published: it depends on the deployment (server compression, caching, CDN, connection and device) rather than on the code, so measure it where it will live.

## Overview

Nook is a complete one-page site for an invented household money app, built so that a buyer can make it their own in an afternoon. A bold colour-blocked identity (one saturated sorbet pink, a deep ink, a warm oat and three bright tones) carries a hero, a pinned feature story, press, a three-step how-it-works, a count-up proof band with reviews, pricing with a monthly and yearly toggle, an FAQ accordion and a closing download block with a QR code.

The centrepiece is a real 3D phone, built in code with three.js rather than a mockup image. It has a satin titanium frame, a frosted glass back in deep petrol blue, a polished camera plateau with three lenses, side buttons, a glass front that reflects a small studio, and a status bar drawn around the dynamic island rather than baked into the screenshots. It stands on the hero with a slight turn, follows the pointer a few degrees, then glides down onto the feature story and stays fixed while it turns a full circle to a new screen for each of four features, with the copy, the stage colour and a step rail changing alongside.

Every screen is an ordinary image referenced by one src in the markup, so replacing the screenshots needs no code. Without WebGL, with reduced motion, with a blocked CDN or with no script, the same four screens appear as flat pictures in a device frame, stacked with their copy. The palette, faces, radii and spacing sit in one token block at the top of style.css, every section is a commented block in index.html, and every place to edit is marked. The README walks through making it yours in thirty minutes.

## Features

- A real 3D phone built in three.js: rounded titanium frame with a bevelled edge, grained frosted glass back, polished camera plateau with three coated lenses, flash and sensor, side buttons, a bottom port and speaker grille, and black glass over the screen
- Physically based materials lit by a studio environment baked in code, so the metal, the glass and the lenses catch real reflections as the phone turns
- One scrubbed timeline keeps the phone pinned while it turns a full circle and swaps its screenshot mid-turn for each of four features, with copy, floating cards, stage colour and a step rail changing alongside
- The phone glides from the hero onto the story stage on scroll, and leaves with it when the story ends
- A small pointer tilt and a slow idle float, with switches to turn either off
- Screens are plain images: change one src per screen and the flat fallback and the 3D display both update, with a bundled HTML screen kit to redraw them; the phone draws a crisp vector status bar that follows each screen's tone
- Hero headline split into masked lines, cards that float, section reveals, a count-up stat band and a how-it-works line that fills as you scroll
- Pricing with a monthly and yearly toggle: prices swap with a roll, plans are repeatable cards and the yearly figures live in the markup
- Keyboard-operable FAQ accordion, pricing toggle and feature rail with visible focus
- A QR block that ships a real, scannable code, and store buttons in plain HTML
- Designed fallback for no WebGL, reduced motion, blocked CDN and no script: the same screens as flat pictures in a device frame, stacked with their copy
- First-class 390px layout: the phone takes the upper half of the pinned stage and the copy steps in a compact panel below it

## Use Cases

- Consumer apps launching on iPhone and Android that need a phone front and centre
- SaaS and productivity tools with a mobile companion
- Fintech, budgeting and banking apps
- Fitness, habit, meditation and wellbeing apps
- Education and language-learning apps
- Startup waitlists and product pages that want a store-button hero

## Questions about this template

### How do I replace the phone screens with my own screenshots?

Each screen is one image tag with a src, one in the hero and one inside every feature step. Change the paths to your own portrait screenshots of any size; the 3D phone crops them to fit without stretching and the flat fallback uses the same file. Leave the top 6.5 percent of each plain, because the phone draws its own status bar there. No code changes are needed. The assets folder also holds an HTML screen kit if you would rather redraw the demo screens.

### Is the phone a 3D model file, and can I change its colour?

It is built entirely in code, so there is no model to license or load. Two tokens at the top of style.css set the titanium frame and the frosted back glass, and the studio light takes a pale tint of your brand colour. Changing them recolours the phone; keep the back deep, as a pale frosted back reads as plastic. The body shape, camera bump and buttons are plain functions in script.js, which is where you would alter the model.

### How do I add a fifth feature or remove one?

Copy a whole step block in the story section, edit its label, headline, copy, tone and screenshot, and save. The rail, step numbers, scroll distance and phone turns are worked out from the number of steps. Delete a block to remove one. Two to six features suit the pacing; the phone turns once per change, and data-spin sets how far.

### How do I set my own prices and plans?

Plans are repeatable cards. Each price holds a monthly and a yearly figure as two spans in the markup, so you type both. A plan with one price, such as Free, needs neither. Copy a card to add a plan or delete one to remove it. The toggle only swaps which span shows, so there is no billing logic, and no payment is taken.

### Do the store buttons and QR code work?

The buttons are plain links with placeholder addresses. Replace each href with your App Store and Google Play URLs. The QR code is a real, scannable image of an example address, so replace assets/qr.svg with a code for your own store page or smart link, or change the src. Nothing is tracked or wired to a store until you do.

### What does a visitor without WebGL see?

The same page with the screenshots as flat pictures in a device frame, and each feature stacked as its own coloured band with its copy. The same happens with reduced motion, a blocked CDN and no script. The 3D phone is an enhancement over a complete page, so check both by trying the site with WebGL switched off.

### How much work is it to make this my own?

About thirty minutes for a first pass: rename the app, repaint the token block, swap the screenshots, then edit the features, pricing and questions. Changing the shape of the phone or adding a new kind of section takes longer. Every place to edit carries an EDIT comment, so searching the folder for that word lists the work.

## Vibe-Code Ready Setup

This template includes `START-HERE-AI.md`, a product-specific copy-paste setup prompt for Cursor, Claude Code, ChatGPT, GitHub Copilot, Windsurf, and other coding assistants. It tells the assistant to inspect the existing stack, integrate the supplied files, preserve the design, scope selectors, retain accessibility and responsive behaviour, add framework-appropriate GSAP cleanup, and report what it tested.

[How AI-assisted setup works](https://gsapvault.com/vibe-coding)

## How It Works

### Structure

One static page in plain sections, each a commented block with a data-section hook and an anchor id. A synchronous head script adds a gate class before first paint, and a second one adds a 3D gate only when the browser has WebGL and motion is allowed. The script takes the classes away again if the phone cannot be built, so the page is always readable.

### The phone

The phone is assembled in code from rounded extrusions and simple primitives: frame, glass, bump, lenses, buttons and a port. A small studio of emissive panels is baked into an environment map, so the materials reflect real light. The screen is a shader that shows one screenshot, or two with a soft wipe between them. One fixed canvas draws it over the page and the script places it on whichever slot in the markup is current.

### Scroll

GSAP writes the phone's played values into one plain pose object: a scrubbed glide from the hero onto the story stage, then one pinned, scrubbed timeline that turns the phone, swells it briefly, swaps the screenshot in the middle of the turn and steps the copy and stage colour. The render loop reads that pose every frame and adds the pointer tilt and idle float itself, so continuous motion and played motion never fight.

### Features are read from the markup

Each feature is a step block holding its copy, its screenshot and its floating cards. The script counts the steps, builds the rail from their labels and sets the scroll distance from their number, so adding or removing a step is a copy or a delete. The pricing toggle and the FAQ work the same way: plans and questions are repeatable blocks the script reads.

### Fallbacks

With reduced motion, no WebGL, a blocked CDN or no script, the flat screenshots show in a simple device frame and every feature is its own coloured band with its copy. Pricing and the FAQ still work whenever GSAP loads, and the FAQ shows every answer open when it does not.

## Documentation

How this template works and how it goes into a page. The reference you use once you own the files (worked examples, events, the programmatic API, the class list) ships with the download.

### Quick Start

**1. Upload the folder.** `index.html`, `assets/style.css`, `assets/script.js` (or `assets/script.min.js`), `assets/qr.svg` and `assets/screens/*.webp` are the whole site. `assets/screens/screen-kit.*` is optional and only used on your machine. Any static host will do.

**2. Check the `<head>`.** Four things must stay, in this order:

_Code snippet omitted: it ships with the download._

The two small scripts must stay synchronous and in `<head>`. The first adds the gate class that stops gated elements painting visible for a frame and then flashing to zero. The second adds `html.gl`, which the stylesheet uses to swap the flat screenshots for the pinned 3D story before first paint. Copy the probe from `index.html` exactly. `data-cfasync="false"` stops Cloudflare Rocket Loader deferring them.

**3. Keep the scripts before `</body>`, in this order:**

_Code snippet omitted: it ships with the download._

three.js loads as an ES module through an import map, in a dynamic import, so a blocked or failed download simply leaves the flat screenshots in place. `assets/script.js` is added by that small module script once three has loaded or failed, so do not add a second `<script src="assets/script.js">`. Lenis is optional; delete its tag and the page scrolls natively. The minimum supported GSAP is 3.12 (SplitText needs 3.13 for masked lines); the demo is built against 3.15.0.

If your site already uses three.js, keep your own import map and make sure `three` resolves to r160 or later; the script only needs `window.THREE` to exist before it runs.

---

### Using It With Your Own Design

#### Make it yours in 30 minutes

Every place you must change is marked. Search the folder for `EDIT:` and you have your to-do list.

**The comment convention** (the same in `index.html`, `style.css` and `script.js`):

| Marker | Meaning |
|---|---|
| `EDIT:` | A string, link, number or image you are expected to change |
| `SECTION:` | The start of one self-contained block, with its `data-section` hook and anchor id. Delete the whole block to remove the section |
| `REPEAT:` | A block to copy to add another, or delete to remove one (a feature step, a plan, a question, a review, a stat) |
| `KEEP:` | A class or `data-` attribute the script or layout relies on. Leave it |

**1. Rename the app (2 minutes).** Search for `Nook`. It appears in the title and description, the nav and footer lockups, the alt texts and screen labels, the footer wordmark (`data-mark`), and the copy. The app icon is the `#mark` symbol at the top of `index.html`: replace its two paths with your logo.

**2. Swap the colours and fonts (5 minutes).** Everything lives in the `:root` block at the top of `assets/style.css`. Change `--brand` first, then `--ink`, `--oat`, and the three feature tones `--sun`, `--mint`, `--sky`. Each colour has an RGB triple beside it; change both. The comment above the tokens lists the measured contrast pairs, so you can see which alpha values must stay. Fonts are `--font-display` and `--font-body`; change the Google Fonts link in `<head>` to match.

**3. Swap the screenshots (5 minutes).** Every phone screen is one `<img data-screen>`: one in the hero and one inside each feature step. Change the `src` to your own portrait screenshot. Any size works (about 1170 by 2532 is ideal); the 3D display cover-fits it, so it is never stretched. The same image is the flat fallback for visitors without WebGL, so write a real `alt`. No code changes.

**4. Edit the features (5 minutes).** Each feature is a `REPEAT` block, a `.step`. Change its `data-tone` (`sun`, `mint`, `sky` or `brand`, or add your own in `style.css`), its label, headline, paragraph, three points, screenshot and floating cards. Copy a whole step to add a feature; delete one to remove it. The step number, the rail, the scroll distance and the phone's turns follow. Two to six features suit the pacing.

**5. Edit pricing and questions (5 minutes).** Each plan is an `article.plan`. A price holds two spans, `data-billing="monthly"` and `data-billing="yearly"`; type both. A plan with one price (Free) needs neither. Add or delete plan cards freely, and add `plan--featured` to the one you want in ink. FAQ items are `.faq-item` blocks; add `data-faq-open` to the one you want open on load.

**6. Wire the store links and the QR code (3 minutes).** Replace the `href` on every `.store-btn` with your App Store and Google Play URLs (the hero and nav buttons scroll to the download block in the demo; point them at the stores if you prefer). Replace `assets/qr.svg` with a QR code for your store page or a smart link, or change its `src`. The bundled code is a real code for an example address, so do not ship it.

**7. Proof and press (5 minutes).** The stat band counts up to whatever number is written in each `[data-count]` element, keeping any prefix or suffix (`£38M`, `2 min`). Press names and reviews are plain text. Replace them with real ones, and remove the section if you have none.

#### Sections and their hooks

| Section | Hook | Anchor | Notes |
|---|---|---|---|
| Nav | `data-section="nav"` | none | A floating pill. `data-nav-optional` links hide on phones |
| Hero | `data-section="hero"` | `#top` | Headline, copy, store buttons, floating cards and the hero phone slot |
| Story | `data-section="story"` | `#features` | The pinned feature story. `data-spin` is the turn between features in degrees (360 by default, 0 for a calm swap) |
| Press | `data-section="press"` | none | A quote and a row of names |
| How | `data-section="how"` | `#how` | Three step cards and a line that fills as you scroll |
| Proof | `data-section="proof"` | `#reviews` | Count-up stats, the store rating and reviews. On the dark ground |
| Pricing | `data-section="pricing"` | `#pricing` | `data-period` on the section is the starting period (`monthly` or `yearly`) |
| FAQ | `data-section="faq"` | `#faq` | An accordion, one open at a time |
| Download | `data-section="download"` | `#download` | Closing headline, store buttons and the QR card |
| Footer | `data-section="footer"` | none | Links, legal line and the decorative wordmark |

Delete any section (the whole block from its `SECTION` comment to its closing tag) and the rest keeps working: every initialiser in `script.js` returns early when its markup is missing, and the nav links to a removed anchor simply do nothing. Remove the matching nav and footer links too.

#### The screens

Each screen is an image. There is nothing to configure: the script collects the hero's `img[data-screen]` and each step's `img[data-screen]`, in page order, and puts them on the phone.

| File | Where it shows |
|---|---|
| `assets/screens/home.webp` | The hero |
| `assets/screens/bills.webp`, `budget.webp`, `nudges.webp`, `goals.webp` | The four feature steps, in order |

Practical notes for your own screenshots:

- **Leave the top 6.5 percent plain.** The phone draws its own status bar (the clock, signal, wifi and battery, placed around the dynamic island and clear of the rounded corners), so a screenshot's top strip should be just the screen's background colour. Paint out a real screenshot's own status bar, or it shows twice. Start headers below the strip and keep them in from the corners.
- **Status bar colour.** The 3D phone measures each screenshot's top edge and draws dark glyphs on a light screen, white on a dark one. The flat fallback cannot measure, so add `data-tone="dark"` to the `<img data-screen>` of a dark screenshot (the step's own `data-tone` is its stage colour, a different thing).
- **Any aspect works.** The display is 9 to 19.5; an image of another ratio is cropped to fill, never stretched.
- **Weight.** Each bundled screen is about 60 to 100 KB as WebP at 1170 by 2532. A 2x export (780 by 1688) is plenty on most screens.
- **The screen kit.** `assets/screens/screen-kit.html` is the plain HTML the bundled screens were made from. Edit it, then in DevTools right-click a `.screen` element and choose Capture node screenshot (at 3x pixel ratio, 1170 by 2532) and save it over the matching file as WebP. The kit leaves the status-bar strip plain for you. It reads the same tokens as the site, so repainting `style.css` repaints it.

#### The phone

The phone is built in code (see `buildPhoneModel` in `script.js`): a bevelled satin titanium frame, a frosted glass back (satin roughness with a fine seeded grain, so the studio lights spread across it as soft highlights), a raised polished-glass camera plateau carrying three machined-metal lenses (recessed black coated glass with a faint green and amber bloom), a muted frosted flash, a lidar sensor and a microphone pinhole, four side buttons, a bottom port and speaker grille, and black glass over the screen with a dynamic island. The display's corners are concentric with the body's (its radius is the body radius minus the bezel width), and the screenshot is clipped to that curve by a rounded-rectangle mask in the screen shader, so the bezel is one even width all the way round. The status bar is drawn as vectors on the display (`drawStatusBar`), centred on the island's line, so it stays crisp at any size and follows each screen's tone through the change between screens. Lit by a small studio baked to an environment map, so the metal and glass catch real reflections.

| Token or attribute | Effect |
|---|---|
| `--phone-frame` | The titanium frame colour. A grey tinted toward the back colour reads as a real colourway |
| `--phone-back` | The frosted back glass colour. Keep it deep: a pale frosted back reads as plastic. The demo is a deep petrol blue (`#1D3441` with a `#5A6870` frame); a forest green (`#22302A` with `#56615B`) or a near-black (`#1C1E22` with `#5C5F66`) also work |
| `--screen-bg` | The colour shown on the display while a screenshot loads |
| `data-status-time` on the hero slot | The clock in the status bar (default 9:41) |
| `data-tilt` on the hero slot | How far the phone is turned in the hero, in radians (default -0.2) |
| `data-idle="0"` on the hero slot | Turns off the idle float |
| `data-intro="0"` on the hero slot | Skips the load entrance |
| `?still=1` in the URL | Both of the above, for screenshots |
| `data-spin` on the story section | Degrees the phone turns between features |

The phone's size and position come from the two empty slots in the markup, `data-phone-slot="hero"` and `data-phone-slot="story"`, which reserve room in the layout; the fixed canvas only draws on top of them. Change a slot's size in CSS (`--phone-h`) and the phone follows.

---

### Palette

Colour is a handful of tokens at the top of `style.css`, each with its RGB triple, so every translucent value is mixed from one source:

| Token | Role |
|---|---|
| `--brand` | Sorbet pink: the hero, the download block, buttons and fills. Never text on oat (2.5:1) |
| `--ink` | Deep teal-black: all type on light grounds, and the dark bands |
| `--oat`, `--oat-2` | The page and its alternate band |
| `--paper`, `--screen-bg` | Card and phone-screen surfaces |
| `--sun`, `--mint`, `--sky` | The feature tones. The story stage cycles through them |
| `--phone-frame`, `--phone-back` | The 3D phone's metal and glass |

Measured contrast is written beside the tokens. On the brand pink use solid ink only; a dimmed ink drops below 4.5:1. `--ink-faint` is for oat and white surfaces; on the bright tones use `--ink-dim`.

### Typeface

Caprasimo (one weight) carries headlines, numerals and the wordmark; Inter at 400, 500, 600 and 700 carries everything else. They are set in `--font-display` and `--font-body`. Any display face with a strong single weight and any legible UI sans will do; check headline wrapping after you change them, because the hero title is sized so each sentence sits on one line.

### Imagery and credits

No photographs are bundled: the phone is 3D, the screens are drawn, and the page has no stock images. Bundled screens are original artwork made with `screen-kit.html`. The QR code encodes an example address. three.js (MIT licence) is loaded from a CDN, and the Caprasimo and Inter fonts (SIL Open Font Licence) from Google Fonts.

---

### Accessibility and fallbacks

- **Keyboard.** The FAQ, the pricing toggle and the feature rail are native buttons with a visible focus ring. The rail jumps to a feature by moving the scroll position. FAQ panels are exposed as regions and hidden from screen readers while closed.
- **Screen readers.** The 3D canvas is decorative and hidden. Every feature's copy is real text in the document, and each flat screenshot has a real `alt`. The pricing toggle announces the period it switches to.
- **Reduced motion.** No 3D phone, no pin, no scrub. Every feature becomes its own coloured band with its copy, its flat screenshot in a device frame and its floating cards; every reveal is visible; counters show their final figures. Pricing and the FAQ still work, without motion.
- **No WebGL.** The same flat, stacked layout, and the console stays clean because WebGL is probed before a renderer is built.
- **No JavaScript, or the CDN blocked.** Everything is readable: the gate class is removed, the screenshots show, the FAQ answers are all open and both pricing periods read as text.
- **Touch and small screens.** The pinned story is redesigned for a phone: the 3D phone takes the upper half of the stage and the copy steps in a compact panel beneath it. The pixel ratio is capped at 1.5 on touch, and the phone geometry uses fewer segments.
- **Smooth scroll.** Lenis is on by default; add `data-smooth="off"` to `<html>` or `?smooth=off` to the address to turn it off. Reduced motion turns it off automatically.

### Browser support

Current Chrome, Safari, Firefox and Edge. The 3D phone needs WebGL 2; every browser without it shows the flat layout. The stage uses `:has()` to paint its first tone before the script runs.

### Performance

One fixed canvas draws the phone, and only while it can be on screen (from the top of the page until the story has scrolled away). It renders at a pixel ratio capped at 2 (1.5 on touch) and the model is about 30 draw calls. The first lever to lower it: cap the ratio at 1.5 in `buildPhone` (`Math.min(window.devicePixelRatio || 1, ...)`). The screenshots are the only heavy assets, so export them at 2x if you need to shave weight.

### Dependencies

GSAP 3.12 or later with ScrollTrigger, plus SplitText 3.13 or later for the masked headline (demo built against 3.15.0); three.js r160 or later as an ES module (demo built against 0.180.0). Lenis 1.3 is optional.

GSAP writes the phone's played motion (the hero-to-story glide, the pinned turn-and-swap timeline and the load entrance) into one pose object, and runs the reveals, count-up, pricing and FAQ. The render loop, not GSAP, owns everything continuous: the pointer tilt, the idle float and the drawing.

### Teardown

Everything runs inside one `gsap.context()` exposed as `window.gsapContext`. Call `window.gsapContext.revert()` to remove the pinned story, the reveals, the listeners, the 3D canvas (its geometry, materials, textures and WebGL context are released) and Lenis if this script started it. A host's own Lenis is left running.

## What You Get

- `index.html`: working demo page
- `assets/script.js`: commented, readable source
- `assets/style.css`: effect styles
- `README.md`: full documentation with examples and framework integration notes
- `START-HERE-AI.md`: product-specific copy-paste prompt for AI-assisted setup
- `LICENSE.txt`: standard license terms
- Lifetime updates: re-download anytime from your library

## Get the Code

This is a premium template. The standard license costs £20 one-time and covers unlimited personal and commercial projects with no attribution required for our code. Bundled third-party assets retain their own licences and attribution requirements. The only restrictions: no redistribution of the code itself and no competing effect libraries.

- [Buy Mobile App Landing](https://gsapvault.com/templates/mobile-app-landing-template)
- [The Vault (£99 one-time, best value): every collection in the Vault library, plus future items added to those collections](https://gsapvault.com/effects)

---

From [GSAP Vault](https://gsapvault.com): production-ready GSAP animation effects. Full catalog for agents: https://gsapvault.com/llms-full.txt
