Growth Stat Chart
Headline, description and three big numbers on the left that count up from zero on entering the viewport and are labeled as sample data; on the right a blue-to-pink-to-orange gradient curve draws left to right with a matching gradient area fading out below.
Taken from the page template Niancheng AI App Builder Home. Use it on its own, or combine it with the other components from the same template to rebuild the full page.
Plain HTML, CSS and a little vanilla JS, with no framework dependency. Copy the prompt into Claude Code, Cursor, Trae or Codex and the model adds Growth Stat Chart to your project in your colors.
Where to use it
Data highlights, growth metrics, counters and stat cards.
Install
With Builder, install it with the 8pt CLI or call it directly from an editor connected to 8pt MCP.
Code
Source for Growth Stat Chart. Motion uses only transform and opacity and respects the Reduce motion setting.
<section class="x-gsc"><div class="gsc-t"><h2>每天,都有人在这里开工</h2><p>世界各地的人每天用念成解决问题、抓住机会。把“总有一天”变成今天。</p><span class="gsc-note">以下为示意数据</span><dl><div><dt>每周新建项目</dt><dd data-to="120" data-u=" 万">—</dd></div><div><dt>累计建成项目</dt><dd data-to="6000" data-u=" 万">—</dd></div><div><dt>成品每月访问量</dt><dd data-to="9" data-u=" 亿">—</dd></div></dl></div><svg class="gsc-ch" viewBox="0 0 700 300" preserveAspectRatio="none" aria-hidden="true"><defs><linearGradient id="gscS" x1="0" x2="1"><stop offset="0" stop-color="#9DB4FF"/><stop offset=".45" stop-color="#5B7CFF"/><stop offset=".7" stop-color="#FF3D8B"/><stop offset="1" stop-color="#FF8A3D"/></linearGradient><linearGradient id="gscF" x1="0" x2="1"><stop offset="0" stop-color="#C7D2FF" stop-opacity=".25"/><stop offset=".55" stop-color="#C9B8FF" stop-opacity=".35"/><stop offset=".8" stop-color="#FF8FC2" stop-opacity=".45"/><stop offset="1" stop-color="#FFB27A" stop-opacity=".5"/></linearGradient><linearGradient id="gscV" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#fff" stop-opacity="1"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><mask id="gscM"><rect width="700" height="300" fill="url(#gscV)"/></mask></defs><path class="gsc-a" d="M0 290 C40 280 60 262 100 258 S 150 256 180 250 S 220 236 250 222 S 290 196 320 186 S 350 182 380 176 S 410 162 430 156 S 460 140 480 126 S 510 104 540 92 S 570 76 590 60 S 620 46 640 40 S 670 26 700 14 L700 300 L0 300 Z" fill="url(#gscF)" mask="url(#gscM)"/><path class="gsc-l" d="M0 290 C40 280 60 262 100 258 S 150 256 180 250 S 220 236 250 222 S 290 196 320 186 S 350 182 380 176 S 410 162 430 156 S 460 140 480 126 S 510 104 540 92 S 570 76 590 60 S 620 46 640 40 S 670 26 700 14" fill="none" stroke="url(#gscS)" stroke-width="2.4" pathLength="1"/></svg></section>
.x-gsc{--ink:#1C1C1A;--mut:#5F5F5B;--line:#E9E7E1;--cream:#FCFBF8;--card:#F5F4EF;--blue:#4C7DFF;--pink:#FF66CC;--red:#FF2E63;--org:#FF7A1A;font-family:"Inter","Noto Sans SC","PingFang SC","Microsoft YaHei",system-ui,sans-serif;-webkit-font-smoothing:antialiased;text-align:left;color:var(--ink)}.x-gsc,.x-gsc *{box-sizing:border-box}.x-gsc a{color:inherit;text-decoration:none}.x-gsc button{font:inherit;cursor:pointer;color:inherit}.x-gsc img{display:block;max-width:100%}.x-gsc{position:relative;width:100%;max-width:1160px;margin:0 auto;padding:20px 20px 40px;min-height:560px}.x-gsc .gsc-t{position:relative;z-index:1;max-width:460px}.x-gsc h2{margin:0 0 14px;font-size:clamp(28px,3vw,36px);font-weight:600;letter-spacing:-.03em;line-height:1.15}.x-gsc .gsc-t>p{margin:0 0 16px;font-size:16px;line-height:1.6;color:var(--mut)}.x-gsc .gsc-note{display:inline-block;font-size:11px;color:#8A8A85;border:1px solid #DDDCD6;border-radius:999px;padding:2px 8px;margin-bottom:22px}.x-gsc dl{margin:0;display:grid;gap:18px}.x-gsc dt{font-size:13px;color:var(--mut)}.x-gsc dd{margin:2px 0 0;font-size:clamp(34px,4vw,48px);font-weight:500;letter-spacing:-.03em;line-height:1.05;font-variant-numeric:tabular-nums}.x-gsc .gsc-ch{position:absolute;right:20px;bottom:30px;width:62%;height:380px;overflow:visible}.x-gsc .gsc-l{stroke-dasharray:1;stroke-dashoffset:1;transition:stroke-dashoffset 2.4s cubic-bezier(.4,0,.2,1)}.x-gsc .gsc-a{opacity:0;transition:opacity 1.6s .8s}.x-gsc.in .gsc-l{stroke-dashoffset:0}.x-gsc.in .gsc-a{opacity:1}@media (max-width:820px){.x-gsc{min-height:0;padding-bottom:20px}.x-gsc .gsc-ch{position:relative;right:auto;bottom:auto;width:100%;height:220px;margin-top:20px}}@media (prefers-reduced-motion:reduce){.x-gsc .gsc-l{stroke-dashoffset:0}.x-gsc .gsc-a{opacity:1}}@media (prefers-reduced-motion:reduce){.x-gsc *,.x-gsc *::before,.x-gsc *::after{animation:none!important;transition:none!important}}.x-gsc{padding:70px 5% 40px;background-image:radial-gradient(rgba(28,28,26,.12) 1.1px,transparent 1.4px);background-size:18px 18px;background-position:center}.x-gsc{width:1200px;max-width:100%;box-sizing:border-box}(root) => {const ds=[...root.querySelectorAll('dd')];let raf;const red=matchMedia('(prefers-reduced-motion: reduce)').matches;
const fmt=(v,u)=>Math.round(v).toLocaleString('zh-CN')+u;
const run=()=>{root.classList.add('in');const t0=performance.now(),D=red?0:1800;const st=t=>{const p=D?Math.min(1,(t-t0)/D):1,e=1-Math.pow(1-p,3);ds.forEach(d=>d.textContent=fmt(+d.dataset.to*e,d.dataset.u));if(p<1)raf=requestAnimationFrame(st)};raf=requestAnimationFrame(st)};
const io=new IntersectionObserver(es=>{if(es.some(e=>e.isIntersecting)){run();io.disconnect()}},{threshold:.3});io.observe(root);
return ()=>{io.disconnect();cancelAnimationFrame(raf)}}