A high-performance, fully animated marketing website for a certified energy auditing firm in Romania. Built with vanilla HTML, CSS, and modular JavaScript — no frameworks, no build tools.
- Hero entrance animations — staggered slide-in and fade-up on load (pure CSS, zero JS dependency)
- Scroll-triggered animations — elements fade/slide into view via
IntersectionObserver - 3D card tilt — perspective tilt with radial shine on service, stat, and testimonial cards
- Parallax hero — background image moves at 38% scroll speed
- Animated counters — numbers count up from 0 with
easeOutExpoeasing - Cursor glow — soft radial glow that follows the cursor with lerp smoothing
- Magnetic buttons — CTAs drift toward the cursor
- Ripple effect — Material Design click ripple on all CTA buttons
- Floating orbs — ambient background orbs with CSS keyframe animation
- Scroll progress bar — gradient bar tracks reading progress at the top
- Sticky header with blur/shadow on scroll
- Smooth scroll with header offset compensation
- Active nav link highlighting based on scroll position
- Mobile drawer with focus trap, Escape key, and body scroll lock
- Full client-side validation (required, email, phone, minlength)
- Real-time error feedback on blur/input
- Formspree integration for real email delivery
- Animated success state on submit
- Newsletter subscription form
prefers-reduced-motionrespected in every animation- Touch device detection — tilt, magnetic, and cursor effects skip on mobile
- Semantic HTML with ARIA labels throughout
- No JavaScript blocking the hero — CSS-only animations above the fold
audit-website/
├── index.html # Markup only — no inline JS or CSS
└── assets/
├── css/
│ └── styles.css # All custom styles + keyframe animations
└── js/
├── main.js # Entry point — imports and calls all inits
├── animations.js # Hero, scroll, parallax, tilt, counters, cursor
├── navigation.js # Scroll progress, header, mobile nav, active links
├── forms.js # Contact form + newsletter validation & submission
└── utils.js # Pure utilities: clamp, throttle, easeOutExpo, showToast
| Layer | Technology |
|---|---|
| Markup | Semantic HTML5 |
| Styling | Tailwind CSS CDN + custom CSS (Material Design 3 color tokens) |
| Typography | Manrope (headlines) + Inter (body) via Google Fonts |
| Icons | Material Symbols Outlined |
| JavaScript | Vanilla ES Modules (no bundler) |
| Forms | Formspree (free tier) |
ES Modules require an HTTP server (they don't work over file://).
# Option 1 — npx serve (no install needed)
npx serve . --listen 3000
# Option 2 — Python
python -m http.server 3000
# Option 3 — VS Code Live Server extension
# Right-click index.html → Open with Live ServerThen open http://localhost:3000
- Create a free account at formspree.io
- Create a new form — you'll get an endpoint like
https://formspree.io/f/xbjnkwpz - Open
assets/js/forms.jsand replace the placeholders:
const FORMSPREE_CONTACT = 'https://formspree.io/f/YOUR_FORM_ID'; // ← replace
const FORMSPREE_NEWSLETTER = 'https://formspree.io/f/YOUR_NEWSLETTER_ID'; // ← replaceWithout this, the form runs in demo mode — it shows the success state locally but doesn't send emails.
Classes hero-a1 through hero-a6 use animation-fill-mode: both so they begin invisible and animate in as soon as the stylesheet loads — no flash of invisible content risk.
hero-a1 → badge pill (fadeSlideLeft, 50ms delay)
hero-a2 → headline (fadeSlideLeft, 180ms delay)
hero-a3 → subtext (fadeSlideLeft, 320ms delay)
hero-a4 → CTA buttons (fadeUpIn, 460ms delay)
hero-a5 → trust strip (fadeUpIn, 580ms delay)
hero-a6 → energy card (fadeUpIn, 300ms delay)
Add data-animate to any element. Optionally add data-animate-variant and animate-stagger-{1-4} classes for directional and staggered entry.
<div data-animate class="animate-hidden animate-stagger-2">...</div>Works in all modern browsers (Chrome, Firefox, Safari, Edge). The filter: blur() backdrop used by the glass card requires Safari 9+ / Chrome 76+.
MIT — free to use and adapt.