Premium Frontend Skill

Build 3D Animated
Mobile-Friendly Websites

Vanilla HTML/CSS/JS, Three.js WebGL, GSAP scroll animations, A-Frame declarative 3D, and Lottie for lightweight motion. Delivers sites that don't look AI-generated.

Three.js GSAP + ScrollTrigger A-Frame Lottie CSS 3D Transforms Higgsfield AI Cloudflare Pages

// Architecture Stack

Each layer serves a specific purpose β€” this is how the pieces fit together.

Design Layerpopular-web-designs skill (54 real brand systems)
3D EngineThree.js β€” vanilla JS, no React required
AnimationGSAP + ScrollTrigger
Declarative 3DA-Frame β€” HTML-first, fallback for simpler 3D
Motion AssetsLottie (JSON from After Effects) or Rive
Images / VideoHiggsfield AI β€” custom generated visuals
HostingCloudflare Pages (wrangler deploy)

01 Three.js β€” Core WebGL (Vanilla JS)

Three.js is the standard for WebGL 3D in the browser. Works with plain HTML/JS β€” no React, no build step. CDN import via jsDelivr.

Setup β€” CDN Import Map (no build step)

// Paste in <head> β€” no npm, no build required
<script type="importmap">
{
  "imports": {
    "three": "https://cdn.jsdelivr.net/npm/three@0.161.0/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.161.0/examples/jsm/"
  }
}
</script>

Basic 3D Scene β€” Scroll-Driven Torus Knot

import * as THREE from 'three';
import { gsap } from 'gsap';
import { ScrollTrigger } 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

// Scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, w/h, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
document.querySelector('#canvas-container').appendChild(renderer.domElement);

// Geometry β€” TorusKnot gives instant premium look
const geometry = new THREE.TorusKnotGeometry(0.5, 0.15, 128, 32);
const material = new THREE.MeshStandardMaterial({
  color: 0xff6b00,
  roughness: 0.2,
  metalness: 0.8
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// Lights
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dirLight = new THREE.DirectionalLight(0xffffff, 2);
dirLight.position.set(5, 5, 5);
scene.add(dirLight);

// Scroll animation β€” geometry rotates as you scroll
gsap.to(mesh.rotation, {
  scrollTrigger: {
    trigger: 'body',
    start: 'top top',
    end: 'bottom bottom',
    scrub: 1
  },
  x: Math.PI * 2,
  y: Math.PI
});

// Render loop
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

// Resize handler
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

Mobile Optimization β€” Three.js

// Cap pixel ratio on mobile β€” GPU killer otherwise
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));

// Detect mobile
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);

// Disable shadows on mobile (expensive)
if (!isMobile) {
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
}

// Lazy load on mobile β€” don't init until visible
const observer = new IntersectionObserver(entries => {
  if (entries[0].isIntersecting) {
    initScene();
    observer.disconnect();
  }
});
observer.observe(document.querySelector('#canvas-container'));

02 GSAP + ScrollTrigger β€” Scroll Animations

GSAP is the animation library. ScrollTrigger makes elements react to scroll position. Works with vanilla JS β€” no React, no build step.

CDN Setup

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>

Scroll-Triggered Reveals

gsap.registerPlugin(ScrollTrigger);

// Staggered section fade + slide
gsap.from('.section', {
  scrollTrigger: {
    trigger: '.section',
    start: 'top 80%',
    toggleActions: 'play none none reverse'
  },
  y: 60,
  opacity: 0,
  duration: 0.8,
  stagger: 0.15,
  ease: 'power2.out'
});

// Hero parallax background
gsap.to('.hero-bg', {
  scrollTrigger: {
    trigger: 'body',
    start: 'top top',
    end: 'bottom bottom',
    scrub: true
  },
  yPercent: 30,
  ease: 'none'
});

// Text clip reveal β€” clips from top to bottom
gsap.from('.reveal-text', {
  scrollTrigger: {
    trigger: '.reveal-text',
    start: 'top 85%'
  },
  clipPath: 'inset(100% 0 0 0)',
  duration: 1.2,
  ease: 'power3.out'
});

Pin + Horizontal Scroll

// Pin section while scrolling horizontally through cards/steps
const sections = document.querySelectorAll('.horizontal-section');
gsap.to(sections, {
  xPercent: -100 * (sections.length - 1),
  ease: 'none',
  scrollTrigger: {
    trigger: '.horizontal-wrapper',
    pin: true,
    scrub: 1,
    snap: 1 / (sections.length - 1),
    end: () => '+=' + document.querySelector('.horizontal-wrapper').offsetWidth
  }
});

Mobile β€” Replace Heavy Animations with Simple Fades

const isMobile = window.innerWidth < 768;

if (isMobile) {
  // Replace scroll-linked 3D with simple fade on mobile
  gsap.from('.section', {
    opacity: 0,
    y: 30,
    duration: 0.5,
    stagger: 0.1
  });
} else {
  init3DScrollAnimations();
}

03 A-Frame β€” Declarative HTML-First 3D

A-Frame builds 3D scenes with pure HTML markup. Good for simpler 3D needs. VR-ready, declarative, no JS required for basic scenes.

CDN Setup

<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>

Basic A-Frame Scene (pure HTML)

<a-scene embedded vr-mode-ui="enabled: false" loading-screen="enabled: false">

  <!-- Lights -->
  <a-entity light="type: ambient; color: #222"></a-entity>
  <a-entity light="type: directional; color: #fff; intensity: 0.8" position="1 3 2"></a-entity>

  <!-- 3D Torus β€” rotating automatically -->
  <a-torus position="0 1.6 -3" rotation="90 0 0"
            color="#FF6B00" radius="0.8" tubular-segments="64"
            animation="property: rotation; to: 90 360 0; dur: 8000; loop: true; easing: linear">
  </a-torus>

  <!-- Box with image texture + floating animation -->
  <a-box position="0 0.8 -2" material="src: #hero-image; shader: flat"
         animation="property: position; to: 0 1.2 -2; dir: alternate; dur: 2000; loop: true">
  </a-box>

  <a-camera position="0 1.6 0"></a-camera>
</a-scene>

<!-- Preload image asset -->
<a-assets>
  <img id="hero-image" src="hero.webp">
</a-assets>

A-Frame + GSAP ScrollTrigger

AFRAME.registerComponent('gsap-scroll', {
  schema: {
    from: { type: 'string' },
    to: { type: 'string' }
  },
  init() {
    const el = this.el;
    gsap.from(el.object3D.position, {
      scrollTrigger: {
        trigger: el.sceneEl,
        start: 'top bottom',
        end: 'center center',
        scrub: 1
      },
      ...JSON.parse(this.data.from)
    });
  }
});

04 Lottie β€” Lightweight Motion Assets

Lottie plays JSON animations exported from After Effects. Tiny file size, infinite scalability, works perfectly on mobile.

CDN Setup

<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js"></script>

Load + Play on Scroll Into View

const anim = lottie.loadAnimation({
  container: document.querySelector('#lottie-container'),
  renderer: 'svg',  // svg = best on mobile
  loop: true,
  autoplay: false,
  path: 'animation.json'  // export from After Effects
});

// Play when scrolled into view
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    entry.isIntersecting ? anim.play() : anim.pause();
  });
}, { threshold: 0.5 });
observer.observe(document.querySelector('#lottie-container'));

Scrub Lottie with Scroll

ScrollTrigger.create({
  trigger: '#lottie-container',
  start: 'top center',
  end: 'bottom center',
  onUpdate: self => {
    anim.goToAndStop(self.progress * anim.totalFrames, true);
  }
});

05 Mobile-First Responsive

Non-negotiable rules for mobile β€” performance and touch targets.

Viewport + Touch Targets

/* Viewport β€” required for mobile */
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

/* Touch targets β€” 44px minimum (Apple/Google standard) */
button, a, .clickable {
  min-height: 44px;
  min-width: 44px;
}

/* Safe area for notched phones (iPhone X+) */
body {
  padding-top: env(safe-area-inset-top);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
}

/* Disable hover effects on touch devices */
@media (hover: none) {
  .hover-effect:hover {
    transform: none !important;
  }
}

CSS 3D Transforms β€” No WebGL Fallback

/* CSS 3D β€” works everywhere, no WebGL needed */
.card-3d {
  transform-style: preserve-3d;
  perspective: 1000px;
}

.card-3d:hover .card-inner {
  transform: rotateY(10deg) rotateX(5deg);
}

.card-inner {
  transition: transform 0.4s ease;
  transform-style: preserve-3d;
}

06 Mobile Performance Checklist

Issue Fix Impact
WebGL on mobile Cap DPR at 1.5, lazy-load with IntersectionObserver High
Heavy GSAP scroll Replace with simple fades on touch devices High
Lottie on mobile Use SVG renderer, preload only when visible Medium
Images WebP format, lazy-load below fold, explicit width/height High
Fonts font-display: swap, preload critical fonts only Medium
Full-screen WebGL Always have CSS 3D fallback on mobile Critical

Lazy Init Pattern

const init3D = () => {
  const canvas = document.createElement('canvas');
  document.querySelector('#hero').appendChild(canvas);
  // Three.js scene setup...
};

// Only load 3D on desktop β€” CSS 3D fallback on mobile
if (window.innerWidth >= 768 && !/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
  init3D();
} else {
  document.querySelector('#hero').classList.add('css-3d-fallback');
}

07 Premium Design System Integration

Pair with the popular-web-designs skill for 54 real brand visual languages. Never design from scratch β€” pick an existing premium system.

Style You Want Use This Design System
Bold dark + motionLinear, Superhuman, Raycast
Editorial luxuryApple, Notion, Stripe
Geometric premiumSpaceX, Vercel, Figma
Warm minimalAirbnb, Spotify, Revolut
Dark SaaS / dev toolsCursor, Sentry, Supabase
Premium lightStripe, Vercel, Cal.com

Example: Stripe-Inspired Design Tokens

const design = {
  colors: {
    primary:   '#635BFF',   // Stripe purple
    accent:    '#0A2540',   // Dark ink
    surface:   '#F6F9FC',   // Light surface
    text:      '#1A1A2E',   // Near black
  },
  typography: {
    fontFamily: 'Source Sans 3, system-ui, sans-serif',
    h1: { size: 'clamp(2.5rem, 5vw, 4rem)', weight: 600 },
    h2: { size: 'clamp(1.5rem, 3vw, 2.5rem)', weight: 600 },
    body:    { size: '1.125rem', weight: 400, lineHeight: 1.7 }
  },
  spacing: {
    section:   'clamp(80px, 12vw, 160px)',
    component: '24px'
  }
};

08 Build Workflow

Step-by-step process for building a premium 3D animated site.

  1. Brief β†’ Choose Design System
    Use popular-web-designs skill to pick a real brand's visual language (e.g. Stripe for B2B SaaS, Airbnb for consumer)
  2. Extract Design Tokens
    Colors, typography scale, spacing system, shadow values from the chosen design system
  3. Hero Concept β†’ Three.js + GSAP
    TorusKnot or custom geometry with metallic material, scroll-driven rotation via ScrollTrigger
  4. Content Sections β†’ CSS 3D + GSAP Reveals
    Staggered fade + slide on scroll, clip-path text reveals, hover tilt on cards
  5. Mobile Check
    Replace 3D scroll with CSS fades on touch devices, cap DPR, lazy-load Three.js
  6. Performance Audit
    WebP images, font-display: swap, 44px touch targets, prefers-reduced-motion
  7. Deploy β†’ Cloudflare Pages
    wrangler pages deploy . --project-name=PROJECT_NAME
  8. Review β†’ Screenshot + Fix
    Browser screenshot check, fix jank, verify on both mobile and desktop
  9. Iterate β†’ /goal Loop Until Premium
    Build β†’ check β†’ fix β†’ deploy β†’ repeat until it passes screenshot review

09 Anti-Slop Rules

What NOT to do β€” these are the markers of AI-generated generic sites.

βœ—
Spinning logos as 3D objects β€” overused, clichΓ©
βœ—
"Floating in space" background with stars or particles
βœ—
Bouncy animations β€” motion must clarify state, not entertain
βœ—
Generic gradient hero β€” use custom generated image or precise geometry
βœ—
Full-screen WebGL on mobile β€” always CSS 3D fallback
βœ“
Respect prefers-reduced-motion β€” disable animations for users who prefer it
βœ“
Custom generated images from Higgsfield AI β€” never stock photos
βœ“
Specific copy written for the offer β€” not generic SaaS buzzwords
/* Disable all animations for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

10 CDN Quick Reference

All libraries load directly from CDN β€” no npm, no build step, no framework lock-in.

Three.js
https://cdn.jsdelivr.net/npm/three@0.161.0/build/three.module.js
GSAP
https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js
ScrollTrigger
https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js
A-Frame
https://aframe.io/releases/1.5.0/aframe.min.js
Lottie
https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js
Inter font
https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700

// Related Skills

SkillWhat It Does
popular-web-designs54 real brand design systems β€” exact colors, typography, CSS values for Stripe, Linear, Apple, etc.
claude-designDesign process + anti-slop rules, variation generation, verification
websitePerformance + accessibility baseline β€” mobile-first, WCAG, semantic HTML
web/firecrawlCompetitor intelligence β€” scrape live sites for layout and copy reference

// Deploy to Cloudflare Pages

# Build locally then deploy with wrangler
cd /root/project-name/
npx wrangler pages deploy . --project-name=PROJECT_NAME --commit-dirty=true
# wrangler.toml β€” tells Cloudflare Pages where to serve from
name = "project-name"
compatibility_date = "2024-01-01"
pages_build_output_dir = "."   # serves index.html at root