076

Mobile App Landing

£20 or the whole Vault, £99

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.

ScrollTriggerSplitText Lenis advanced
10 more details
webgl-shaderpinningscrubsplit-textcount-upaccordionpointer-tiltprocedural-3dkeyboard-navigationform-animation

This template reads better at your own screen size than in the frame below:

Released

About this template

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.

Read the full template overview

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.

Mobile App Landing - website template preview

What's included

12 items
  • 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

Perfect for

6 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

How it works

5 sections

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.

Plugins ScrollTrigger, SplitText
Difficulty Advanced
Smooth scroll Lenis integration
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this template's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

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.

Paid template

Purchase to unlock the code.

Buying Mobile App Landing opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£20 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

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.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.