Single-file build — HTML + CSS + vanilla JS + Three.js particle hero. 305 lines, 19 KB. Zero backend, zero tracking.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Sable</title>
<meta name="description" content="Sable — the AI analytics platform that turns raw signal into foresight.">
<meta name="robots" content="noindex">
<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=Sora:wght@500;600;700&family=Manrope:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{
--bg:#06070d; --bg2:#0a0c15; --panel:rgba(255,255,255,.028); --line:rgba(140,155,200,.14);
--ink:#eef1fa; --mute:#9aa4bd; --dim:#5f6883;
--teal:#5eead4; --indigo:#8b8cf9; --violet:#b078ff;
--disp:'Sora',system-ui,sans-serif; --body:'Manrope',system-ui,sans-serif; --mono:'IBM Plex Mono',ui-monospace,monospace;
--max:1180px;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--body);-webkit-font-smoothing:antialiased;line-height:1.55;overflow-x:hidden}
a{color:inherit;text-decoration:none}
h1,h2,h3{font-family:var(--disp);font-weight:600;letter-spacing:-.02em;text-wrap:balance;margin:0}
.wrap{max-width:var(--max);margin:0 auto;padding:0 26px}
.eyebrow{font-family:var(--mono);font-size:12px;letter-spacing:.24em;text-transform:uppercase;color:var(--teal)}
.btn{display:inline-flex;align-items:center;gap:9px;font-family:var(--disp);font-weight:600;font-size:14.5px;
padding:12px 22px;border-radius:8px;cursor:pointer;border:1px solid transparent;transition:transform .15s,box-shadow .2s,background .2s}
.btn-p{background:linear-gradient(100deg,var(--teal),var(--indigo));color:#06070d;box-shadow:0 6px 30px rgba(94,234,212,.22)}
.btn-p:hover{transform:translateY(-2px);box-shadow:0 10px 40px rgba(139,140,249,.35)}
.btn-g{border-color:var(--line);color:var(--ink);background:rgba(255,255,255,.02)}
.btn-g:hover{border-color:rgba(140,155,200,.4);background:rgba(255,255,255,.05)}
/* nav */
nav{position:fixed;top:0;left:0;right:0;z-index:50;backdrop-filter:blur(14px);background:rgba(6,7,13,.55);border-bottom:1px solid transparent;transition:border-color .3s,background .3s}
nav.scrolled{border-bottom-color:var(--line);background:rgba(6,7,13,.82)}
.nav-in{display:flex;align-items:center;justify-content:space-between;height:66px}
.logo{display:flex;align-items:center;gap:11px;font-family:var(--disp);font-weight:700;font-size:19px;letter-spacing:-.01em}
.mark{width:26px;height:26px;border-radius:7px;background:linear-gradient(135deg,var(--teal),var(--indigo));display:grid;place-items:center;box-shadow:0 0 20px rgba(94,234,212,.4)}
.mark:before{content:'';width:9px;height:9px;background:#06070d;border-radius:2px;transform:rotate(45deg)}
.nav-links{display:flex;gap:30px;font-size:14px;color:var(--mute)}
.nav-links a:hover{color:var(--ink)}
@media(max-width:820px){.nav-links{display:none}}
/* hero */
.hero{position:relative;min-height:100vh;display:flex;align-items:center;padding-top:66px;overflow:hidden}
#scene{position:absolute;inset:0;z-index:0}
.glow{position:absolute;z-index:0;width:900px;height:900px;top:-160px;right:-220px;border-radius:50%;
background:radial-gradient(circle,rgba(94,234,212,.14),rgba(139,140,249,.08) 40%,transparent 66%);filter:blur(20px);pointer-events:none}
.hero-grid{position:relative;z-index:2;display:grid;grid-template-columns:1.05fr .95fr;gap:20px;align-items:center;width:100%}
@media(max-width:900px){.hero-grid{grid-template-columns:1fr}}
.hero h1{font-size:clamp(38px,6vw,72px);line-height:1.02;font-weight:700;margin:20px 0 0}
.hero h1 .grad{background:linear-gradient(100deg,var(--teal),var(--indigo) 55%,var(--violet));-webkit-background-clip:text;background-clip:text;color:transparent}
.lead{color:var(--mute);font-size:clamp(16px,2vw,19px);max-width:40ch;margin:22px 0 30px}
.cta-row{display:flex;gap:14px;flex-wrap:wrap}
.trust{display:flex;gap:34px;margin-top:44px;flex-wrap:wrap}
.trust .n{font-family:var(--disp);font-weight:700;font-size:26px}
.trust .l{font-size:12.5px;color:var(--dim);font-family:var(--mono);letter-spacing:.05em}
.scrollcue{position:absolute;bottom:26px;left:50%;transform:translateX(-50%);z-index:2;font-family:var(--mono);font-size:11px;letter-spacing:.3em;color:var(--dim);text-transform:uppercase}
/* sections */
section{position:relative;z-index:1}
.band{padding:110px 0}
.sec-head{max-width:620px;margin-bottom:52px}
.sec-head h2{font-size:clamp(28px,4vw,44px);line-height:1.08;margin-top:14px}
.sec-head p{color:var(--mute);font-size:17px;margin:16px 0 0}
.features{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
@media(max-width:900px){.features{grid-template-columns:1fr}}
.card{border:1px solid var(--line);border-radius:14px;padding:26px;background:linear-gradient(180deg,var(--panel),transparent);transition:border-color .25s,transform .25s}
.card:hover{border-color:rgba(94,234,212,.35);transform:translateY(-3px)}
.card .ic{width:42px;height:42px;border-radius:10px;display:grid;place-items:center;border:1px solid var(--line);color:var(--teal);margin-bottom:18px}
.card h3{font-size:19px;margin-bottom:9px}
.card p{color:var(--mute);font-size:14.5px;margin:0}
.card .k{font-family:var(--mono);font-size:11px;color:var(--dim);letter-spacing:.16em;text-transform:uppercase;display:block;margin-bottom:14px}
/* split showcase */
.split{display:grid;grid-template-columns:1fr 1fr;gap:56px;align-items:center}
@media(max-width:900px){.split{grid-template-columns:1fr;gap:34px}}
.panel-box{border:1px solid var(--line);border-radius:16px;background:linear-gradient(160deg,rgba(94,234,212,.05),rgba(139,140,249,.04));padding:22px;position:relative;overflow:hidden}
.panel-box .row{display:flex;justify-content:space-between;align-items:center;padding:12px 4px;border-bottom:1px solid var(--line);font-size:13.5px}
.panel-box .row:last-child{border-bottom:none}
.panel-box .tag{font-family:var(--mono);font-size:11px;padding:3px 9px;border-radius:20px;border:1px solid var(--line);color:var(--teal)}
.panel-box .tag.warn{color:var(--violet);border-color:rgba(176,120,255,.4)}
.chart{height:120px;margin:14px 0 4px}
.split ul{list-style:none;padding:0;margin:22px 0 0}
.split li{display:flex;gap:13px;padding:11px 0;color:var(--mute);font-size:15px;align-items:flex-start}
.split li b{color:var(--ink);font-weight:600}
.dot{width:7px;height:7px;border-radius:50%;background:var(--teal);margin-top:8px;flex:0 0 auto;box-shadow:0 0 8px var(--teal)}
/* stats band */
.statband{border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:var(--bg2)}
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;padding:56px 0}
@media(max-width:760px){.stats{grid-template-columns:repeat(2,1fr);gap:34px}}
.stat .n{font-family:var(--disp);font-weight:700;font-size:clamp(30px,4vw,46px);background:linear-gradient(120deg,var(--teal),var(--indigo));-webkit-background-clip:text;background-clip:text;color:transparent}
.stat .l{color:var(--mute);font-size:13.5px;margin-top:6px}
/* cta */
.cta{text-align:center;position:relative;overflow:hidden}
.cta .glow2{position:absolute;inset:0;z-index:0;background:radial-gradient(600px 300px at 50% 0%,rgba(139,140,249,.16),transparent 70%)}
.cta-in{position:relative;z-index:1}
.cta h2{font-size:clamp(30px,5vw,52px);line-height:1.05}
.cta p{color:var(--mute);font-size:18px;max-width:46ch;margin:18px auto 32px}
footer{border-top:1px solid var(--line);padding:44px 0;color:var(--dim);font-size:13.5px}
.foot-in{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;align-items:center}
.foot-links{display:flex;gap:24px}
.foot-links a:hover{color:var(--ink)}
.reveal{opacity:0;transform:translateY(22px);transition:opacity .7s cubic-bezier(.2,.7,.2,1),transform .7s cubic-bezier(.2,.7,.2,1)}
.reveal.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.reveal{opacity:1;transform:none;transition:none}}
</style>
</head>
<body>
<nav id="nav"><div class="wrap nav-in">
<div class="logo"><span class="mark"></span>Sable</div>
<div class="nav-links">
<a href="#platform">Platform</a><a href="#signal">Signal Engine</a><a href="#numbers">Results</a><a href="#start">Pricing</a>
</div>
<a class="btn btn-g" href="#start">Request access</a>
</div></nav>
<header class="hero">
<div id="scene"></div>
<div class="glow"></div>
<div class="wrap hero-grid">
<div>
<span class="eyebrow">Predictive analytics · autonomous</span>
<h1>See the number<br>before it <span class="grad">moves.</span></h1>
<p class="lead">Sable is the AI analytics platform that reads every stream your business runs on, separates signal from noise, and tells you what happens next — in plain language, in real time.</p>
<div class="cta-row">
<a class="btn btn-p" href="#start">Request access →</a>
<a class="btn btn-g" href="#platform">See the platform</a>
</div>
<div class="trust">
<div><div class="n">2.4B</div><div class="l">events / day</div></div>
<div><div class="n">98.6%</div><div class="l">forecast precision</div></div>
<div><div class="n"><300ms</div><div class="l">signal latency</div></div>
</div>
</div>
<div></div>
</div>
<div class="scrollcue">Scroll</div>
</header>
<section id="platform" class="band">
<div class="wrap">
<div class="sec-head reveal">
<span class="eyebrow">The platform</span>
<h2>One layer of intelligence over all of your data.</h2>
<p>Connect a warehouse, a stream, or a spreadsheet. Sable models it in minutes and starts surfacing what your dashboards can't.</p>
</div>
<div class="features">
<div class="card reveal"><div class="ic">◇</div><span class="k">Forecasting</span><h3>Predictive models, self-tuning</h3><p>Sable builds and retrains a forecast for every metric that matters, adapting the moment your data shifts — no data-science team required.</p></div>
<div class="card reveal"><div class="ic">◈</div><span class="k">Detection</span><h3>Anomalies, caught early</h3><p>It watches millions of series at once and flags the one moving wrong hours before it shows up on a chart — with the likely cause attached.</p></div>
<div class="card reveal"><div class="ic">◆</div><span class="k">Language</span><h3>Ask in plain English</h3><p>“Why did churn spike in the Nordics?” Sable answers with the drivers, the confidence, and the evidence — not another query to write.</p></div>
</div>
</div>
</section>
<section id="signal" class="band" style="padding-top:20px">
<div class="wrap split">
<div class="reveal">
<span class="eyebrow">Signal engine</span>
<h2 style="font-size:clamp(28px,4vw,42px);line-height:1.08;margin-top:14px">Foresight, not hindsight.</h2>
<ul>
<li><span class="dot"></span><span><b>Live signal, not batch reports.</b> Streaming inference scores every event as it lands — sub-300ms from source to insight.</span></li>
<li><span class="dot"></span><span><b>Cause, not just correlation.</b> Sable traces the drivers behind a move and ranks them by impact and confidence.</span></li>
<li><span class="dot"></span><span><b>Explainable by design.</b> Every forecast ships with the evidence behind it, so your team acts on it without second-guessing.</span></li>
</ul>
</div>
<div class="reveal">
<div class="panel-box">
<div class="row"><span style="font-family:var(--mono);font-size:12px;color:var(--mute)">signal / revenue.eu</span><span class="tag">▲ forecast +6.2%</span></div>
<canvas class="chart" id="spark"></canvas>
<div class="row"><span>Churn · Nordics</span><span class="tag warn">anomaly · 2h early</span></div>
<div class="row"><span>Pipeline velocity</span><span class="tag">stable · 94% conf</span></div>
<div class="row"><span>Ad spend efficiency</span><span class="tag warn">drift detected</span></div>
</div>
</div>
</div>
</section>
<div class="statband" id="numbers"><div class="wrap"><div class="stats">
<div class="stat reveal"><div class="n">40×</div><div class="l">faster to first insight</div></div>
<div class="stat reveal"><div class="n">6 hrs</div><div class="l">average early-warning lead</div></div>
<div class="stat reveal"><div class="n">120+</div><div class="l">connectors, zero code</div></div>
<div class="stat reveal"><div class="n">$1.2B</div><div class="l">revenue steered in 2025</div></div>
</div></div></div>
<section class="band">
<div class="wrap split">
<div class="reveal">
<div class="panel-box" style="background:linear-gradient(160deg,rgba(176,120,255,.06),rgba(94,234,212,.04))">
<div style="font-family:var(--mono);font-size:12px;color:var(--mute);margin-bottom:12px">// natural-language query</div>
<div style="font-size:16px;color:var(--ink);margin-bottom:16px">“Where are we leaking margin this quarter?”</div>
<div style="border-top:1px solid var(--line);padding-top:14px;font-size:14.5px;color:var(--mute);line-height:1.7">
<span style="color:var(--teal)">Sable</span> — Fulfilment in <b style="color:var(--ink)">DE-South</b> is the leak: expedited-shipping share rose 3.1× after a carrier SLA change on Aug 4. Projected margin drag <b style="color:var(--ink)">-$418k</b> by quarter close. Confidence 91%.
</div>
</div>
</div>
<div class="reveal">
<span class="eyebrow">Built for the room where it's decided</span>
<h2 style="font-size:clamp(28px,4vw,42px);line-height:1.08;margin-top:14px">From raw stream to the decision, in one breath.</h2>
<p style="color:var(--mute);font-size:16px;margin-top:16px">No pipelines to babysit, no dashboards to reverse-engineer. Sable sits over your stack and hands the people who decide a clear, evidenced answer — the moment it matters.</p>
<div class="cta-row" style="margin-top:26px"><a class="btn btn-g" href="#start">Book a walkthrough</a></div>
</div>
</div>
</section>
<section id="start" class="band cta">
<div class="glow2"></div>
<div class="wrap cta-in">
<span class="eyebrow">Limited early access</span>
<h2 style="margin-top:16px">Put the next quarter<br>in front of you.</h2>
<p>Sable is onboarding a small cohort of data-serious teams. Bring one metric that keeps you up at night — we'll forecast it live.</p>
<a class="btn btn-p" href="#" style="font-size:16px;padding:15px 30px">Request access →</a>
</div>
</section>
<footer><div class="wrap foot-in">
<div class="logo" style="font-size:16px"><span class="mark" style="width:22px;height:22px"></span>Sable</div>
<div class="foot-links"><a href="#platform">Platform</a><a href="#signal">Signal Engine</a><a href="#start">Access</a><a href="#">Security</a></div>
<div>© 2026 Sable Intelligence</div>
</div></footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.160.0/three.min.js"></script>
<script>
(function(){
"use strict";
var io=new IntersectionObserver(function(es){es.forEach(function(e){if(e.isIntersecting){e.target.classList.add('in');io.unobserve(e.target);}});},{threshold:.14});
document.querySelectorAll('.reveal').forEach(function(el){io.observe(el);});
var nav=document.getElementById('nav');
addEventListener('scroll',function(){nav.classList.toggle('scrolled',scrollY>20);},{passive:true});
(function(){
var c=document.getElementById('spark'); if(!c)return; var ctx=c.getContext('2d');
function draw(){
var w=c.clientWidth,h=c.clientHeight,dpr=Math.min(2,devicePixelRatio||1); c.width=w*dpr;c.height=h*dpr;ctx.setTransform(dpr,0,0,dpr,0,0);
ctx.clearRect(0,0,w,h);
var pts=[],n=48; for(var i=0;i<n;i++){var t=i/(n-1); pts.push([t*w, h*(0.75-0.42*Math.sin(t*7)*Math.exp(-t*0.4)-t*0.28)]);}
var g=ctx.createLinearGradient(0,0,w,0); g.addColorStop(0,'#5eead4');g.addColorStop(1,'#8b8cf9');
var fill=ctx.createLinearGradient(0,0,0,h); fill.addColorStop(0,'rgba(94,234,212,.28)');fill.addColorStop(1,'rgba(94,234,212,0)');
ctx.beginPath();ctx.moveTo(pts[0][0],pts[0][1]); pts.forEach(function(p){ctx.lineTo(p[0],p[1]);});
ctx.lineTo(w,h);ctx.lineTo(0,h);ctx.closePath();ctx.fillStyle=fill;ctx.fill();
ctx.beginPath();ctx.moveTo(pts[0][0],pts[0][1]); pts.forEach(function(p){ctx.lineTo(p[0],p[1]);});
ctx.strokeStyle=g;ctx.lineWidth=2.2;ctx.lineJoin='round';ctx.stroke();
var last=pts[pts.length-1]; ctx.beginPath();ctx.arc(last[0],last[1],3.4,0,7);ctx.fillStyle='#8b8cf9';ctx.shadowColor='#8b8cf9';ctx.shadowBlur=12;ctx.fill();ctx.shadowBlur=0;
}
draw(); addEventListener('resize',draw);
})();
if(!window.THREE) return;
var reduce=matchMedia('(prefers-reduced-motion:reduce)').matches;
var host=document.getElementById('scene');
var renderer=new THREE.WebGLRenderer({antialias:true,alpha:true,powerPreference:'high-performance'});
renderer.setPixelRatio(Math.min(2,devicePixelRatio||1));
var scene=new THREE.Scene();
var cam=new THREE.PerspectiveCamera(52,1,.1,100); cam.position.set(0,0,15.5);
host.appendChild(renderer.domElement);
var N=reduce?1400:3200, R=7.6, pos=new Float32Array(N*3), col=new Float32Array(N*3), rnd=new Float32Array(N);
var ga=Math.PI*(3-Math.sqrt(5)), cA=new THREE.Color(0x5eead4), cB=new THREE.Color(0x8b8cf9), cC=new THREE.Color(0xb078ff), tmp=new THREE.Color();
for(var i=0;i<N;i++){
var y=1-(i/(N-1))*2, r=Math.sqrt(1-y*y), th=ga*i;
pos[i*3]=Math.cos(th)*r*R; pos[i*3+1]=y*R; pos[i*3+2]=Math.sin(th)*r*R;
var m=(y+1)/2; tmp.copy(m<0.5?cA:cB).lerp(m<0.5?cB:cC,(m%0.5)*2);
col[i*3]=tmp.r;col[i*3+1]=tmp.g;col[i*3+2]=tmp.b; rnd[i]=Math.random()*6.28;
}
var geo=new THREE.BufferGeometry();
geo.setAttribute('position',new THREE.BufferAttribute(pos,3));
geo.setAttribute('color',new THREE.BufferAttribute(col,3));
geo.setAttribute('aRnd',new THREE.BufferAttribute(rnd,1));
var mat=new THREE.ShaderMaterial({
transparent:true,depthWrite:false,blending:THREE.AdditiveBlending,
uniforms:{uT:{value:0}},
vertexShader:'attribute float aRnd;varying vec3 vC;uniform float uT;void main(){vC=color;vec4 mv=modelViewMatrix*vec4(position,1.);float tw=.6+.4*sin(uT*1.5+aRnd);gl_PointSize=(1.7+1.7*tw)*(300./-mv.z);gl_Position=projectionMatrix*mv;}',
fragmentShader:'varying vec3 vC;void main(){vec2 d=gl_PointCoord-vec2(.5);float a=smoothstep(.5,.0,length(d));gl_FragColor=vec4(vC,a);}',
vertexColors:true
});
var pts=new THREE.Points(geo,mat); scene.add(pts);
var D=reduce?200:600, dp=new Float32Array(D*3);
for(var j=0;j<D;j++){dp[j*3]=(Math.random()-.5)*40;dp[j*3+1]=(Math.random()-.5)*26;dp[j*3+2]=(Math.random()-.5)*20-6;}
var dg=new THREE.BufferGeometry();dg.setAttribute('position',new THREE.BufferAttribute(dp,3));
var dust=new THREE.Points(dg,new THREE.PointsMaterial({color:0x8b8cf9,size:.045,transparent:true,opacity:.5,depthWrite:false}));
scene.add(dust);
var mx=0,my=0,tmx=0,tmy=0;
addEventListener('pointermove',function(e){tmx=(e.clientX/innerWidth-.5);tmy=(e.clientY/innerHeight-.5);},{passive:true});
function size(){var w=host.clientWidth,h=host.clientHeight;renderer.setSize(w,h,false);cam.aspect=w/h;cam.updateProjectionMatrix();}
size(); addEventListener('resize',size);
var t0=performance.now();
(function loop(now){
var t=(now-t0)/1000; mat.uniforms.uT.value=t;
mx+=(tmx-mx)*.04; my+=(tmy-my)*.04;
if(!reduce){pts.rotation.y=t*.08+mx*.5; pts.rotation.x=-.15+my*.35; dust.rotation.y=t*.02;}
else{pts.rotation.y=mx*.5;pts.rotation.x=-.15+my*.35;}
renderer.render(scene,cam); requestAnimationFrame(loop);
})(t0);
})();
</script>
</body></html>