AI Product — Voice AI Landing
A calm, futuristic one-page marketing site for a fictional voice AI product, built in vanilla HTML, CSS and JS. It pairs a deep indigo palette with pastel waveform accents, an animated hero orb, and a press-to-talk demo. Sections cover assistants, dubbing and accessibility use cases, a play-to-hear voices showcase with a live reacting waveform, a three-step API walkthrough, monthly and annual pricing, testimonials, an email capture CTA, and a footer.
MCP
Code
/* ============ Vox — Voice AI landing ============ */
:root {
--ink-900: #070a1f;
--ink-800: #0c1130;
--ink-700: #111842;
--ink-600: #1a2256;
--line: rgba(150, 165, 255, 0.14);
--text: #eef1ff;
--muted: #9aa3d4;
--indigo: #6b7bff;
--indigo-2: #8a78ff;
--mint: #7ce0d3;
--lilac: #c9a0ff;
--peach: #ffb47c;
--grad: linear-gradient(110deg, #8a78ff, #6b7bff 40%, #7ce0d3);
--shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.7);
--radius: 18px;
--maxw: 1140px;
--ease: cubic-bezier(.22,.61,.36,1);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: "Plus Jakarta Sans", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
background: radial-gradient(1200px 700px at 80% -10%, #1a2156 0%, transparent 55%),
radial-gradient(900px 600px at -10% 10%, #14224a 0%, transparent 50%),
var(--ink-900);
color: var(--text);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
overflow-x: hidden;
}
h1, h2, h3, h4 { line-height: 1.1; margin: 0; letter-spacing: -0.02em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
img, canvas { max-width: 100%; display: block; }
.wrap { width: min(var(--maxw), 92vw); margin-inline: auto; }
.muted { color: var(--muted); }
.grad { background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
/* ---- buttons ---- */
.btn {
--pad: .7rem 1.15rem;
display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
padding: var(--pad); border-radius: 999px; font-weight: 600; font-size: .95rem;
border: 1px solid transparent; cursor: pointer; transition: transform .2s var(--ease), box-shadow .2s, background .2s, border-color .2s;
white-space: nowrap;
}
.btn:active { transform: translateY(1px) scale(.99); }
.btn-lg { padding: .9rem 1.5rem; font-size: 1rem; }
.btn-block { width: 100%; }
.btn-primary { background: var(--grad); color: #0a0d22; box-shadow: 0 10px 30px -10px rgba(107,123,255,.7); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 16px 40px -12px rgba(124,224,211,.55); }
.btn-ghost { background: rgba(255,255,255,.04); color: var(--text); border-color: var(--line); }
.btn-ghost:hover { background: rgba(255,255,255,.09); transform: translateY(-2px); }
/* ---- nav ---- */
.nav {
position: sticky; top: 0; z-index: 50;
backdrop-filter: blur(14px);
border-bottom: 1px solid transparent;
transition: background .3s, border-color .3s;
}
.nav.scrolled { background: rgba(8,11,28,.72); border-bottom-color: var(--line); }
.nav-inner { display: flex; align-items: center; justify-content: space-between; padding: .85rem 0; }
.logo { display: inline-flex; align-items: center; gap: .55rem; font-weight: 800; font-size: 1.25rem; }
.logo-orb {
width: 22px; height: 22px; border-radius: 50%;
background: var(--grad); box-shadow: 0 0 18px rgba(124,224,211,.6);
animation: pulse 3s var(--ease) infinite;
}
@keyframes pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.15); } }
.nav-links { display: flex; align-items: center; gap: 1.6rem; }
.nav-links > a:not(.btn) { color: var(--muted); font-weight: 500; font-size: .95rem; transition: color .2s; }
.nav-links > a:not(.btn):hover { color: var(--text); }
.nav-toggle { display: none; flex-direction: column; gap: 5px; background: none; border: 0; cursor: pointer; padding: 8px; }
.nav-toggle span { width: 24px; height: 2px; background: var(--text); border-radius: 2px; transition: .3s; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* ---- hero ---- */
.hero { position: relative; padding: clamp(3rem, 8vw, 6.5rem) 0 clamp(2.5rem, 6vw, 4.5rem); overflow: hidden; }
.hero-glow {
position: absolute; inset: -20% 0 auto 0; height: 600px; pointer-events: none;
background: radial-gradient(600px 360px at 70% 30%, rgba(138,120,255,.35), transparent 70%),
radial-gradient(500px 300px at 30% 50%, rgba(124,224,211,.22), transparent 70%);
filter: blur(10px);
}
.hero-inner { position: relative; display: grid; grid-template-columns: 1.1fr .9fr; gap: 3rem; align-items: center; }
.eyebrow {
display: inline-block; font-size: .8rem; font-weight: 600; letter-spacing: .04em;
color: var(--mint); background: rgba(124,224,211,.1); border: 1px solid rgba(124,224,211,.25);
padding: .4rem .8rem; border-radius: 999px; margin-bottom: 1.3rem;
}
.hero h1 { font-size: clamp(2.4rem, 5.4vw, 4rem); font-weight: 800; }
.lead { font-size: clamp(1.05rem, 1.6vw, 1.25rem); color: var(--muted); max-width: 34ch; margin: 1.2rem 0 1.8rem; }
.hero-actions { display: flex; gap: .8rem; flex-wrap: wrap; }
.hero-meta { display: flex; gap: 1.6rem; margin-top: 2rem; flex-wrap: wrap; color: var(--muted); font-size: .92rem; }
.hero-meta strong { color: var(--text); font-size: 1.05rem; }
/* orb */
.hero-orb-wrap { display: flex; flex-direction: column; align-items: center; gap: 1.8rem; }
.orb { position: relative; width: 320px; height: 320px; display: grid; place-items: center; }
.orb-core {
position: absolute; width: 230px; height: 230px; border-radius: 50%;
background: radial-gradient(circle at 35% 30%, #aeb6ff, #6b7bff 45%, #3a2f8f 100%);
box-shadow: 0 0 90px rgba(107,123,255,.55), inset 0 0 60px rgba(255,255,255,.18);
animation: float 6s ease-in-out infinite;
}
.orb.live .orb-core { animation: float 6s ease-in-out infinite, glow 1.2s ease-in-out infinite; }
@keyframes float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes glow { 0%,100% { box-shadow: 0 0 90px rgba(107,123,255,.55), inset 0 0 60px rgba(255,255,255,.18); } 50% { box-shadow: 0 0 130px rgba(124,224,211,.75), inset 0 0 70px rgba(255,255,255,.3); } }
.orb-ring {
position: absolute; width: 300px; height: 300px; border-radius: 50%;
border: 1px solid rgba(150,165,255,.3); border-top-color: var(--mint);
animation: spin 9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.orb canvas { position: relative; z-index: 2; width: 280px; height: 110px; }
.talk-btn {
display: inline-flex; align-items: center; gap: .7rem;
background: rgba(255,255,255,.05); border: 1px solid var(--line); color: var(--text);
padding: .7rem 1.3rem; border-radius: 999px; font: inherit; font-weight: 600; cursor: pointer;
transition: .2s var(--ease);
}
.talk-btn:hover { background: rgba(255,255,255,.1); }
.talk-btn .talk-dot { width: 12px; height: 12px; border-radius: 50%; background: var(--peach); transition: .2s; }
.talk-btn[aria-pressed="true"] { border-color: var(--mint); box-shadow: 0 0 0 4px rgba(124,224,211,.15); }
.talk-btn[aria-pressed="true"] .talk-dot { background: var(--mint); animation: blink .8s infinite; }
@keyframes blink { 50% { opacity: .25; } }
/* ---- logos ---- */
.logos { padding: 2.5rem 0; border-block: 1px solid var(--line); }
.logos-label { text-align: center; color: var(--muted); font-size: .85rem; letter-spacing: .08em; text-transform: uppercase; margin-bottom: 1.4rem; }
.logos-row { display: flex; justify-content: center; gap: clamp(1.5rem, 5vw, 3.5rem); flex-wrap: wrap; }
.logo-mark { font-weight: 700; font-size: 1.2rem; color: var(--muted); opacity: .7; letter-spacing: -.02em; transition: .2s; }
.logo-mark:hover { opacity: 1; color: var(--text); }
/* ---- generic section ---- */
.section { padding: clamp(3.5rem, 8vw, 6rem) 0; }
.section-head { max-width: 640px; margin-bottom: 2.6rem; }
.kicker { color: var(--mint); font-weight: 600; font-size: .85rem; letter-spacing: .08em; text-transform: uppercase; }
.section-head h2 { font-size: clamp(1.8rem, 3.6vw, 2.7rem); font-weight: 800; margin: .6rem 0 .8rem; }
.grid { display: grid; gap: 1.4rem; }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.card {
background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.015));
border: 1px solid var(--line); border-radius: var(--radius); padding: 1.7rem;
transition: transform .25s var(--ease), border-color .25s, box-shadow .25s;
}
.card:hover { transform: translateY(-6px); border-color: rgba(124,224,211,.4); box-shadow: var(--shadow); }
.card-icon { font-size: 1.8rem; width: 56px; height: 56px; display: grid; place-items: center; border-radius: 14px; background: rgba(107,123,255,.14); margin-bottom: 1rem; }
.card h3 { font-size: 1.25rem; margin-bottom: .5rem; }
.card p { color: var(--muted); }
.ticks { list-style: none; padding: 0; margin: 1rem 0 0; display: grid; gap: .5rem; }
.ticks li { position: relative; padding-left: 1.5rem; color: var(--muted); font-size: .92rem; }
.ticks li::before { content: "✓"; position: absolute; left: 0; color: var(--mint); font-weight: 700; }
/* ---- voices ---- */
.voices-grid { display: grid; grid-template-columns: .8fr 1.2fr; gap: 1.6rem; }
.voice-list { display: flex; flex-direction: column; gap: .7rem; }
.voice-pill {
display: flex; align-items: center; gap: .7rem; text-align: left;
background: rgba(255,255,255,.03); border: 1px solid var(--line); color: var(--text);
padding: 1rem 1.1rem; border-radius: 14px; font: inherit; font-weight: 600; cursor: pointer;
transition: .2s var(--ease);
}
.voice-pill em { color: var(--muted); font-weight: 400; font-style: normal; font-size: .85rem; margin-left: auto; }
.voice-pill .dot { width: 11px; height: 11px; border-radius: 50%; background: var(--c); box-shadow: 0 0 12px var(--c); }
.voice-pill:hover { background: rgba(255,255,255,.07); }
.voice-pill.is-active { border-color: rgba(124,224,211,.5); background: rgba(124,224,211,.08); }
.voice-stage {
background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.02));
border: 1px solid var(--line); border-radius: var(--radius); padding: 1.7rem;
}
.voice-stage-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.2rem; }
.voice-stage-top h3 { font-size: 1.5rem; }
.play-btn {
width: 56px; height: 56px; border-radius: 50%; border: 0; cursor: pointer;
background: var(--grad); display: grid; place-items: center; transition: .2s var(--ease);
box-shadow: 0 10px 26px -10px rgba(107,123,255,.8);
}
.play-btn:hover { transform: scale(1.07); }
.play-tri { width: 0; height: 0; border-left: 14px solid #0a0d22; border-top: 9px solid transparent; border-bottom: 9px solid transparent; margin-left: 3px; }
.play-btn[aria-pressed="true"] .play-tri { border: 0; width: 14px; height: 14px; background: #0a0d22; border-radius: 2px; margin: 0; }
#voiceWave { width: 100%; height: 160px; border-radius: 12px; background: rgba(0,0,0,.25); }
.voice-sample { margin-top: 1.1rem; color: var(--muted); font-style: italic; }
/* ---- how ---- */
.steps { display: grid; grid-template-columns: repeat(3,1fr); gap: 1.4rem; }
.step { background: rgba(255,255,255,.025); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.7rem; transition: .25s var(--ease); }
.step:hover { border-color: rgba(138,120,255,.4); transform: translateY(-4px); }
.step-no { font-family: "JetBrains Mono", monospace; font-size: 1.3rem; color: var(--lilac); }
.step h3 { margin: .6rem 0 .5rem; font-size: 1.2rem; }
.step p { color: var(--muted); }
.code {
margin-top: 1rem; background: var(--ink-900); border: 1px solid var(--line); border-radius: 12px;
padding: .9rem 1rem; font-family: "JetBrains Mono", monospace; font-size: .82rem; color: var(--mint);
overflow-x: auto;
}
/* ---- pricing ---- */
.bill-toggle { display: flex; align-items: center; gap: .8rem; margin-top: 1.2rem; color: var(--muted); font-weight: 600; font-size: .95rem; }
.bill-toggle .save { color: var(--mint); font-style: normal; font-size: .82rem; }
.switch { width: 46px; height: 26px; border-radius: 999px; background: rgba(255,255,255,.12); border: 1px solid var(--line); cursor: pointer; position: relative; transition: .25s; }
.switch[aria-checked="true"] { background: var(--grad); }
.switch .knob { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: #fff; transition: .25s var(--ease); }
.switch[aria-checked="true"] .knob { left: 22px; }
.plans .plan {
background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.015));
border: 1px solid var(--line); border-radius: var(--radius); padding: 1.9rem; position: relative;
transition: .25s var(--ease);
}
.plan:hover { transform: translateY(-5px); }
.plan.featured { border-color: rgba(124,224,211,.55); box-shadow: var(--shadow); }
.badge { position: absolute; top: -12px; right: 1.4rem; background: var(--grad); color: #0a0d22; font-size: .72rem; font-weight: 700; padding: .3rem .7rem; border-radius: 999px; }
.plan h3 { font-size: 1.3rem; }
.price { font-size: 2.4rem; font-weight: 800; margin: .7rem 0 .3rem; letter-spacing: -.03em; }
.price .per { font-size: 1rem; font-weight: 500; color: var(--muted); }
.plan .ticks { margin: 1.2rem 0 1.6rem; }
/* ---- testimonials ---- */
.quote { margin: 0; background: rgba(255,255,255,.03); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.7rem; transition: .25s var(--ease); }
.quote:hover { border-color: rgba(138,120,255,.4); transform: translateY(-4px); }
.quote blockquote { margin: 0 0 1.2rem; font-size: 1.05rem; }
.quote figcaption { display: flex; align-items: center; gap: .8rem; }
.quote figcaption > span:last-child { display: flex; flex-direction: column; font-weight: 600; font-size: .95rem; }
.quote small { color: var(--muted); font-weight: 400; }
.av { width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: .85rem; color: #0a0d22; background: var(--c); flex: none; }
/* ---- cta ---- */
.cta { padding: clamp(3.5rem,8vw,6rem) 0; }
.cta-inner {
text-align: center; background: linear-gradient(135deg, rgba(138,120,255,.18), rgba(124,224,211,.12));
border: 1px solid var(--line); border-radius: 28px; padding: clamp(2.5rem,5vw,4rem);
}
.cta-inner h2 { font-size: clamp(1.9rem,4vw,3rem); font-weight: 800; }
.cta-inner > .muted { margin: .8rem auto 1.8rem; max-width: 44ch; }
.cta-form { display: flex; gap: .7rem; justify-content: center; flex-wrap: wrap; max-width: 460px; margin: 0 auto; }
.cta-form input {
flex: 1; min-width: 220px; padding: .9rem 1.1rem; border-radius: 999px;
background: rgba(0,0,0,.3); border: 1px solid var(--line); color: var(--text); font: inherit;
}
.cta-form input:focus { outline: none; border-color: var(--mint); box-shadow: 0 0 0 3px rgba(124,224,211,.18); }
.cta-fine { margin-top: 1rem; font-size: .82rem; }
/* ---- footer ---- */
.footer { border-top: 1px solid var(--line); padding-top: 3rem; margin-top: 1rem; }
.footer-inner { display: flex; justify-content: space-between; gap: 2rem; flex-wrap: wrap; padding-bottom: 2.5rem; }
.footer-brand { max-width: 260px; }
.footer-brand .muted { margin-top: .8rem; }
.footer-cols { display: flex; gap: 3rem; flex-wrap: wrap; }
.footer-cols h4 { font-size: .9rem; margin-bottom: .9rem; }
.footer-cols a { display: block; color: var(--muted); font-size: .9rem; margin-bottom: .5rem; transition: .2s; }
.footer-cols a:hover { color: var(--text); }
.footer-base { display: flex; justify-content: space-between; padding: 1.5rem 0; border-top: 1px solid var(--line); font-size: .85rem; flex-wrap: wrap; gap: .5rem; }
/* ---- toast ---- */
.toast {
position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 130%);
background: #fff; color: #0a0d22; font-weight: 600; padding: .8rem 1.3rem; border-radius: 12px;
box-shadow: var(--shadow); z-index: 100; transition: transform .35s var(--ease); max-width: 90vw;
}
.toast.show { transform: translate(-50%, 0); }
/* ---- reveal ---- */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity .6s var(--ease), transform .6s var(--ease); }
.reveal.in { opacity: 1; transform: none; }
/* ---- responsive ---- */
@media (max-width: 980px) {
.grid-3, .steps { grid-template-columns: 1fr 1fr; }
.hero-inner { grid-template-columns: 1fr; text-align: center; }
.lead, .hero-meta { margin-inline: auto; }
.hero-actions, .hero-meta { justify-content: center; }
.voices-grid { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
.nav-links {
position: fixed; inset: 60px 0 auto 0; flex-direction: column; align-items: stretch; gap: .4rem;
background: rgba(8,11,28,.97); border-bottom: 1px solid var(--line); padding: 1rem 6vw 1.5rem;
transform: translateY(-130%); transition: transform .3s var(--ease); backdrop-filter: blur(14px);
}
.nav-links.open { transform: none; }
.nav-links > a:not(.btn) { padding: .6rem 0; }
.nav-links .btn { width: 100%; }
.nav-toggle { display: flex; }
.grid-3, .steps { grid-template-columns: 1fr; }
.footer-inner { flex-direction: column; }
}
@media (max-width: 520px) {
.orb { width: 260px; height: 260px; }
.orb-core { width: 190px; height: 190px; }
.orb-ring { width: 240px; height: 240px; }
.hero-meta { gap: 1rem; }
.cta-form { flex-direction: column; }
.cta-form input, .cta-form .btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
html { scroll-behavior: auto; }
}/* ============ Vox — Voice AI landing · vanilla JS ============ */
(function () {
"use strict";
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () { toastEl.classList.remove("show"); }, 2600);
}
/* ---------- sticky nav style ---------- */
var nav = document.getElementById("nav");
function onScroll() {
if (window.scrollY > 12) nav.classList.add("scrolled");
else nav.classList.remove("scrolled");
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- mobile menu ---------- */
var toggle = document.getElementById("navToggle");
var navLinks = document.getElementById("navLinks");
toggle.addEventListener("click", function () {
var open = navLinks.classList.toggle("open");
toggle.setAttribute("aria-expanded", String(open));
});
navLinks.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
navLinks.classList.remove("open");
toggle.setAttribute("aria-expanded", "false");
});
});
/* ---------- scroll reveal ---------- */
var reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); }
});
}, { threshold: 0.12 });
reveals.forEach(function (el) { io.observe(el); });
} else {
reveals.forEach(function (el) { el.classList.add("in"); });
}
/* ---------- generic waveform renderer ---------- */
function makeWave(canvas, opts) {
opts = opts || {};
var ctx = canvas.getContext("2d");
var dpr = Math.min(window.devicePixelRatio || 1, 2);
var W = canvas.width, H = canvas.height;
function resize() {
var rect = canvas.getBoundingClientRect();
if (rect.width) {
W = canvas.width = Math.round(rect.width * dpr);
H = canvas.height = Math.round(rect.height * dpr);
}
}
resize();
window.addEventListener("resize", resize);
var bars = opts.bars || 48;
var amp = 0; // 0..1 envelope
var targetAmp = opts.idle != null ? opts.idle : 0.18;
var speed = opts.speed || 1.4;
var phase = Math.random() * 10;
var color1 = opts.c1 || "#8a78ff";
var color2 = opts.c2 || "#7ce0d3";
var raf;
function draw(t) {
ctx.clearRect(0, 0, W, H);
amp += (targetAmp - amp) * 0.08;
var grad = ctx.createLinearGradient(0, 0, W, 0);
grad.addColorStop(0, color1);
grad.addColorStop(1, color2);
ctx.fillStyle = grad;
var bw = (W / bars) * 0.55;
var gap = W / bars;
for (var i = 0; i < bars; i++) {
var n = Math.sin(i * 0.5 + t * 0.004 * speed + phase) * 0.5 +
Math.sin(i * 0.17 - t * 0.006 * speed) * 0.5;
var h = (Math.abs(n) * 0.5 + 0.12) * amp * H;
h = Math.max(h, dpr * 2);
var x = i * gap + (gap - bw) / 2;
var y = (H - h) / 2;
var r = Math.min(bw / 2, h / 2);
roundRect(ctx, x, y, bw, h, r);
}
raf = requestAnimationFrame(draw);
}
function roundRect(c, x, y, w, h, r) {
c.beginPath();
c.moveTo(x + r, y);
c.arcTo(x + w, y, x + w, y + h, r);
c.arcTo(x + w, y + h, x, y + h, r);
c.arcTo(x, y + h, x, y, r);
c.arcTo(x, y, x + w, y, r);
c.closePath();
c.fill();
}
raf = requestAnimationFrame(draw);
return {
setActive: function (on) { targetAmp = on ? (opts.active || 0.95) : (opts.idle != null ? opts.idle : 0.18); },
setSpeed: function (s) { speed = s; },
setColors: function (a, b) { color1 = a; color2 = b; }
};
}
/* ---------- hero orb wave + press to talk ---------- */
var heroWave = makeWave(document.getElementById("heroWave"), { bars: 40, idle: 0.25, active: 0.9, c1: "#aeb6ff", c2: "#7ce0d3" });
var orb = document.getElementById("orb");
var talkBtn = document.getElementById("talkBtn");
var talkLabel = talkBtn.querySelector(".talk-label");
var talking = false;
var talkTimer;
talkBtn.addEventListener("click", function () {
talking = !talking;
talkBtn.setAttribute("aria-pressed", String(talking));
orb.classList.toggle("live", talking);
heroWave.setActive(talking);
talkLabel.textContent = talking ? "Listening…" : "Press to talk";
clearTimeout(talkTimer);
if (talking) {
toast("🎙️ Listening — say something (demo)");
talkTimer = setTimeout(function () {
talking = false;
talkBtn.setAttribute("aria-pressed", "false");
orb.classList.remove("live");
heroWave.setActive(false);
talkLabel.textContent = "Press to talk";
toast("✨ \"How can I help today?\"");
}, 4200);
}
});
/* ---------- voices showcase ---------- */
var voiceWave = makeWave(document.getElementById("voiceWave"), { bars: 64, idle: 0.12, active: 0.92, c1: "#8a78ff", c2: "#7ce0d3" });
var pills = document.querySelectorAll(".voice-pill");
var voiceName = document.getElementById("voiceName");
var voiceNameInline = document.getElementById("voiceNameInline");
var voiceDesc = document.getElementById("voiceDesc");
var playBtn = document.getElementById("playBtn");
var playing = false;
var playTimer;
var voiceColors = {
Aria: ["#8a78ff", "#aeb6ff"],
Nico: ["#7ce0d3", "#aef0e6"],
Sable: ["#c9a0ff", "#8a78ff"],
Wren: ["#ffb47c", "#ffd9b0"]
};
function stopPlay() {
playing = false;
playBtn.setAttribute("aria-pressed", "false");
voiceWave.setActive(false);
clearTimeout(playTimer);
}
pills.forEach(function (pill) {
pill.addEventListener("click", function () {
pills.forEach(function (p) { p.classList.remove("is-active"); p.setAttribute("aria-selected", "false"); });
pill.classList.add("is-active");
pill.setAttribute("aria-selected", "true");
var name = pill.dataset.voice;
voiceName.textContent = name;
voiceNameInline.textContent = name;
voiceDesc.textContent = pill.dataset.desc;
voiceWave.setSpeed(parseFloat(pill.dataset.speed) || 1.4);
var c = voiceColors[name] || ["#8a78ff", "#7ce0d3"];
voiceWave.setColors(c[0], c[1]);
stopPlay();
});
});
playBtn.addEventListener("click", function () {
playing = !playing;
playBtn.setAttribute("aria-pressed", String(playing));
voiceWave.setActive(playing);
if (playing) {
toast("▶ Playing " + voiceName.textContent + " (demo)");
playTimer = setTimeout(stopPlay, 3600);
}
});
/* ---------- pricing toggle ---------- */
var billSwitch = document.getElementById("billSwitch");
var amounts = document.querySelectorAll(".amt");
billSwitch.addEventListener("click", function () {
var annual = billSwitch.getAttribute("aria-checked") !== "true";
billSwitch.setAttribute("aria-checked", String(annual));
amounts.forEach(function (el) {
var v = annual ? el.dataset.a : el.dataset.m;
el.textContent = /^\d+$/.test(v) ? "$" + v : v;
});
toast(annual ? "Annual pricing — save 20%" : "Switched to monthly");
});
/* ---------- CTA form ---------- */
var ctaForm = document.getElementById("ctaForm");
ctaForm.addEventListener("submit", function (e) {
e.preventDefault();
var email = document.getElementById("ctaEmail").value.trim();
toast("🔑 API key sent to " + (email || "your inbox") + " (demo)");
ctaForm.reset();
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Vox — Voice AI for humans</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- NAV -->
<header class="nav" id="nav">
<div class="wrap nav-inner">
<a class="logo" href="#top" aria-label="Vox home">
<span class="logo-orb" aria-hidden="true"></span>
<span>Vox</span>
</a>
<nav class="nav-links" id="navLinks" aria-label="Primary">
<a href="#voices">Voices</a>
<a href="#use-cases">Use cases</a>
<a href="#how">How it works</a>
<a href="#pricing">Pricing</a>
<a class="btn btn-ghost" href="#cta">Sign in</a>
<a class="btn btn-primary" href="#cta">Start free</a>
</nav>
<button class="nav-toggle" id="navToggle" aria-label="Toggle menu" aria-expanded="false" aria-controls="navLinks">
<span></span><span></span><span></span>
</button>
</div>
</header>
<main id="top">
<!-- HERO -->
<section class="hero">
<div class="hero-glow" aria-hidden="true"></div>
<div class="wrap hero-inner">
<div class="hero-copy reveal">
<span class="eyebrow">Realtime neural voice · v3</span>
<h1>Give your product a <span class="grad">voice people trust</span>.</h1>
<p class="lead">Vox turns text into lifelike, emotionally aware speech — and listens back in real time. Build assistants, dub films, and make experiences accessible in 42 languages.</p>
<div class="hero-actions">
<a class="btn btn-primary btn-lg" href="#cta">Start building free</a>
<a class="btn btn-ghost btn-lg" href="#voices">Hear the voices</a>
</div>
<div class="hero-meta">
<span><strong>120ms</strong> latency</span>
<span><strong>42</strong> languages</span>
<span><strong>4.9★</strong> on G2</span>
</div>
</div>
<div class="hero-orb-wrap reveal">
<div class="orb" id="orb" role="img" aria-label="Animated voice visualization">
<div class="orb-core"></div>
<div class="orb-ring"></div>
<canvas id="heroWave" width="320" height="120" aria-hidden="true"></canvas>
</div>
<button class="talk-btn" id="talkBtn" aria-pressed="false">
<span class="talk-dot" aria-hidden="true"></span>
<span class="talk-label">Press to talk</span>
</button>
</div>
</div>
</section>
<!-- LOGOS -->
<section class="logos" aria-label="Trusted by">
<div class="wrap">
<p class="logos-label">Powering voice at forward teams</p>
<div class="logos-row">
<span class="logo-mark">Northwind</span>
<span class="logo-mark">Lumen</span>
<span class="logo-mark">Cadence</span>
<span class="logo-mark">Orbital</span>
<span class="logo-mark">Penrose</span>
<span class="logo-mark">Vela</span>
</div>
</div>
</section>
<!-- USE CASES -->
<section class="section" id="use-cases">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">Use cases</span>
<h2>One voice engine, endless surfaces.</h2>
<p class="muted">From customer support to feature films, Vox adapts its tone, pace, and emotion to fit the moment.</p>
</div>
<div class="grid grid-3">
<article class="card reveal">
<div class="card-icon" aria-hidden="true">🎧</div>
<h3>Voice assistants</h3>
<p>Ship conversational agents that interrupt, backchannel, and respond in under 150ms — they sound like teammates, not robots.</p>
<ul class="ticks">
<li>Realtime barge-in</li>
<li>Function calling</li>
<li>Memory & persona control</li>
</ul>
</article>
<article class="card reveal">
<div class="card-icon" aria-hidden="true">🎬</div>
<h3>Dubbing & media</h3>
<p>Localize video into 42 languages while preserving the original performer's timbre, cadence, and emotion frame-accurately.</p>
<ul class="ticks">
<li>Lip-sync timing</li>
<li>Voice cloning consent</li>
<li>Studio-grade export</li>
</ul>
</article>
<article class="card reveal">
<div class="card-icon" aria-hidden="true">♿</div>
<h3>Accessibility</h3>
<p>Turn any interface into a screen-reader-class experience with natural narration, reading speed control, and dyslexia-aware pacing.</p>
<ul class="ticks">
<li>WCAG-aligned output</li>
<li>Adjustable pacing</li>
<li>SSML & phoneme tuning</li>
</ul>
</article>
</div>
</div>
</section>
<!-- VOICES SHOWCASE -->
<section class="section voices" id="voices">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">Voices</span>
<h2>Pick a voice. Press play.</h2>
<p class="muted">Every voice reacts live — watch the waveform breathe as it speaks.</p>
</div>
<div class="voices-grid">
<div class="voice-list reveal" role="tablist" aria-label="Voice library">
<button class="voice-pill is-active" role="tab" aria-selected="true" data-voice="Aria" data-desc="Warm · narration" data-speed="1.4">
<span class="dot" style="--c:#7c8cff"></span> Aria <em>Warm narration</em>
</button>
<button class="voice-pill" role="tab" aria-selected="false" data-voice="Nico" data-desc="Bright · assistant" data-speed="2.1">
<span class="dot" style="--c:#7ce0d3"></span> Nico <em>Bright assistant</em>
</button>
<button class="voice-pill" role="tab" aria-selected="false" data-voice="Sable" data-desc="Deep · cinematic" data-speed="0.9">
<span class="dot" style="--c:#c9a0ff"></span> Sable <em>Deep cinematic</em>
</button>
<button class="voice-pill" role="tab" aria-selected="false" data-voice="Wren" data-desc="Soft · accessibility" data-speed="1.1">
<span class="dot" style="--c:#ffb47c"></span> Wren <em>Soft & clear</em>
</button>
</div>
<div class="voice-stage reveal">
<div class="voice-stage-top">
<div>
<h3 id="voiceName">Aria</h3>
<p class="muted" id="voiceDesc">Warm · narration</p>
</div>
<button class="play-btn" id="playBtn" aria-pressed="false" aria-label="Play voice sample">
<span class="play-tri" aria-hidden="true"></span>
</button>
</div>
<canvas id="voiceWave" width="640" height="160" aria-hidden="true"></canvas>
<p class="voice-sample">“Hi there — I'm <span id="voiceNameInline">Aria</span>. Let me read this for you.”</p>
</div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section class="section how" id="how">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">How it works</span>
<h2>From text to talking in three calls.</h2>
</div>
<div class="steps">
<div class="step reveal">
<span class="step-no">01</span>
<h3>Stream text in</h3>
<p>Send tokens as they generate. Vox starts speaking before your sentence is finished.</p>
<pre class="code"><code>vox.speak({ voice: "aria",
text: stream })</code></pre>
</div>
<div class="step reveal">
<span class="step-no">02</span>
<h3>Shape the emotion</h3>
<p>Nudge tone, speed, and stability with simple controls — or let the model infer mood from context.</p>
<pre class="code"><code>style: { emotion: "calm",
pace: 0.9 }</code></pre>
</div>
<div class="step reveal">
<span class="step-no">03</span>
<h3>Get audio out</h3>
<p>Receive a low-latency PCM stream you can pipe straight to the browser, phone, or your DAW.</p>
<pre class="code"><code>audio.play(vox.stream)
// 120ms to first byte</code></pre>
</div>
</div>
</div>
</section>
<!-- PRICING -->
<section class="section pricing" id="pricing">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">Pricing</span>
<h2>Pay for what you speak.</h2>
<div class="bill-toggle" role="group" aria-label="Billing period">
<span>Monthly</span>
<button class="switch" id="billSwitch" role="switch" aria-checked="false" aria-label="Toggle annual billing"><span class="knob"></span></button>
<span>Annual <em class="save">−20%</em></span>
</div>
</div>
<div class="grid grid-3 plans">
<article class="plan reveal">
<h3>Hobby</h3>
<p class="price"><span class="amt" data-m="0" data-a="0">$0</span><span class="per">/mo</span></p>
<p class="muted">For tinkering and demos.</p>
<ul class="ticks">
<li>10k characters / month</li>
<li>8 starter voices</li>
<li>Community support</li>
</ul>
<a class="btn btn-ghost btn-block" href="#cta">Start free</a>
</article>
<article class="plan featured reveal">
<span class="badge">Most popular</span>
<h3>Studio</h3>
<p class="price"><span class="amt" data-m="49" data-a="39">$49</span><span class="per">/mo</span></p>
<p class="muted">For products in production.</p>
<ul class="ticks">
<li>2M characters / month</li>
<li>All 60+ voices + cloning</li>
<li>120ms realtime API</li>
<li>Priority support</li>
</ul>
<a class="btn btn-primary btn-block" href="#cta">Start 14-day trial</a>
</article>
<article class="plan reveal">
<h3>Scale</h3>
<p class="price"><span class="amt" data-m="Custom" data-a="Custom">Custom</span></p>
<p class="muted">For platforms & studios.</p>
<ul class="ticks">
<li>Unlimited characters</li>
<li>Dedicated voices & SLA</li>
<li>On-prem & VPC options</li>
<li>Solutions engineer</li>
</ul>
<a class="btn btn-ghost btn-block" href="#cta">Talk to sales</a>
</article>
</div>
</div>
</section>
<!-- TESTIMONIALS -->
<section class="section testimonials">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">Loved by builders</span>
<h2>What teams say after shipping.</h2>
</div>
<div class="grid grid-3">
<figure class="quote reveal">
<blockquote>“We replaced our old TTS in a weekend. Support calls now feel human — our CSAT jumped 14 points.”</blockquote>
<figcaption><span class="av" style="--c:#7c8cff">MK</span><span>Maya Khan<small>Head of CX, Northwind</small></span></figcaption>
</figure>
<figure class="quote reveal">
<blockquote>“Dubbing a 40-minute doc into six languages used to take three weeks. Vox did it overnight, in the same voice.”</blockquote>
<figcaption><span class="av" style="--c:#7ce0d3">DR</span><span>Diego Ruiz<small>Producer, Lumen Studios</small></span></figcaption>
</figure>
<figure class="quote reveal">
<blockquote>“Our blind users finally describe the app as ‘pleasant to listen to.' That sentence is the whole win.”</blockquote>
<figcaption><span class="av" style="--c:#ffb47c">PA</span><span>Priya Anand<small>Accessibility lead, Cadence</small></span></figcaption>
</figure>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta" id="cta">
<div class="wrap cta-inner reveal">
<h2>Hear your product speak today.</h2>
<p class="muted">10,000 free characters. No credit card. Two minutes to your first words.</p>
<form class="cta-form" id="ctaForm">
<label class="sr-only" for="ctaEmail">Work email</label>
<input id="ctaEmail" type="email" placeholder="[email protected]" required />
<button class="btn btn-primary btn-lg" type="submit">Get API key</button>
</form>
<p class="cta-fine muted">By signing up you agree to our fictional terms.</p>
</div>
</section>
</main>
<!-- FOOTER -->
<footer class="footer">
<div class="wrap footer-inner">
<div class="footer-brand">
<a class="logo" href="#top"><span class="logo-orb" aria-hidden="true"></span><span>Vox</span></a>
<p class="muted">Realtime neural voice for every product.</p>
</div>
<nav class="footer-cols" aria-label="Footer">
<div><h4>Product</h4><a href="#voices">Voices</a><a href="#pricing">Pricing</a><a href="#how">API docs</a></div>
<div><h4>Company</h4><a href="#top">About</a><a href="#top">Careers</a><a href="#top">Blog</a></div>
<div><h4>Legal</h4><a href="#top">Privacy</a><a href="#top">Terms</a><a href="#top">Consent</a></div>
</nav>
</div>
<div class="wrap footer-base">
<span class="muted">© 2026 Vox Labs · Illustrative demo</span>
<span class="muted">Built with vanilla JS</span>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Voice AI Landing
A full single-page landing for Vox, a fictional realtime neural-voice product. The design leans into a deep indigo and navy backdrop lit with soft pastel waveform accents — calm, futuristic, and human. A sticky glass nav sits over a hero that features an animated floating orb, a canvas waveform, and a “press to talk” button that flips the orb into a live, glowing listening state with rolling captions delivered through a toast helper.
Below the hero, a social-proof logo strip leads into three use-case cards (voice assistants, dubbing and media, accessibility), then a voices showcase where each voice pill retunes the live canvas waveform’s color and speed and the play button animates a sample reading. A three-step “how it works” walkthrough shows code snippets, followed by a pricing block with a monthly/annual toggle that rewrites the numbers, customer testimonials, an email-capture CTA, and a footer.
Everything is vanilla — no frameworks or build step. The waveforms are drawn on <canvas> with
requestAnimationFrame, interactions use a single IntersectionObserver for scroll reveals, and the
layout is fully responsive down to ~360px with a mobile menu toggle. Motion is disabled under
prefers-reduced-motion.
Illustrative UI only — fictional brand, not a real product.