Wireframe Globe Arc
A dotted wireframe globe drawn on canvas rotates slowly, with nearer dots brighter and larger; a pink-to-blue gradient arc keeps tracing between two points and a blue-pink glow breathes at the bottom. Title and description sit top left. A good backdrop for global availability.
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 Wireframe Globe Arc to your project in your colors.
Where to use it
Background layers for heroes, login pages and launch pages: adds texture to large empty areas without competing with the content.
Install
With Builder, install it with the 8pt CLI or call it directly from an editor connected to 8pt MCP.
Code
Source for Wireframe Globe Arc. Motion uses only transform and opacity and respects the Reduce motion setting.
<section class="x-wga"><canvas class="glb" aria-hidden="true"></canvas><span class="wga-glow"></span><div class="wga-cap"><h3>随时随地,都能用</h3><p>网页、平板与手机自动适配,访客在哪儿打开都顺手。</p></div></section>
.x-wga{--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-wga,.x-wga *{box-sizing:border-box}.x-wga a{color:inherit;text-decoration:none}.x-wga button{font:inherit;cursor:pointer;color:inherit}.x-wga img{display:block;max-width:100%}.x-wga{position:relative;width:100%;max-width:1100px;height:640px;margin:0 auto;border-radius:22px;background:radial-gradient(60% 60% at 50% 45%,#202128,#141518);box-shadow:inset 0 0 0 1px rgba(255,255,255,.07);overflow:hidden;color:#fff}.x-wga .glb{position:absolute;left:0;top:0;width:100%;height:88%}.x-wga .wga-glow{position:absolute;left:-10%;right:-10%;bottom:-30%;height:55%;border-radius:50%;background:radial-gradient(closest-side,#B9CBFF,#4C6FFF 45%,rgba(255,102,204,.45) 72%,transparent);filter:blur(24px);animation:wgaG 6s ease-in-out infinite alternate}@keyframes wgaG{to{transform:scale(1.06);opacity:.8}}.x-wga .wga-cap{position:absolute;left:34px;top:30px;max-width:340px}.x-wga h3{margin:0 0 6px;font-size:20px;font-weight:600;letter-spacing:-.02em}.x-wga p{margin:0;font-size:13.5px;line-height:1.6;color:#AFAFAA}@media (max-width:640px){.x-wga{height:480px}}@media (prefers-reduced-motion:reduce){.x-wga *,.x-wga *::before,.x-wga *::after{animation:none!important;transition:none!important}}.x-wga{background-image:radial-gradient(rgba(255,255,255,.09) 1px,transparent 1.4px),radial-gradient(60% 60% at 50% 45%,#202128,#141518);background-size:16px 16px,100% 100%;height:700px}.x-wga{width:1100px;max-width:100%;box-sizing:border-box}(root) => {const drawGlobe=(cv)=>{const ctx=cv.getContext('2d');const N=220,P=[],E=[];const ga=Math.PI*(3-Math.sqrt(5));for(let i=0;i<N;i++){const y=1-(i/(N-1))*2,r=Math.sqrt(1-y*y),t=ga*i;P.push([Math.cos(t)*r,y,Math.sin(t)*r])}
for(let i=0;i<N;i++)for(let j=i+1;j<N;j++){const dx=P[i][0]-P[j][0],dy=P[i][1]-P[j][1],dz=P[i][2]-P[j][2];if(dx*dx+dy*dy+dz*dz<0.058)E.push([i,j])}
const ll=(la,lo)=>{la*=Math.PI/180;lo*=Math.PI/180;return [Math.cos(la)*Math.cos(lo),Math.sin(la),Math.cos(la)*Math.sin(lo)]};const A=ll(28,-60),B=ll(-12,40);
let W=0,H=0,dpr=1,raf,a=0,prog=0;const red=matchMedia('(prefers-reduced-motion: reduce)').matches;
const fit=()=>{dpr=Math.min(2,devicePixelRatio||1);W=cv.clientWidth;H=cv.clientHeight;cv.width=W*dpr;cv.height=H*dpr};fit();const ro=new ResizeObserver(fit);ro.observe(cv);
const rot=(p)=>{const c=Math.cos(a),s=Math.sin(a),t=0.32,ct=Math.cos(t),st=Math.sin(t);let x=p[0]*c-p[2]*s,z=p[0]*s+p[2]*c,y=p[1];const y2=y*ct-z*st,z2=y*st+z*ct;return [x,y2,z2]};
const frame=()=>{ctx.setTransform(dpr,0,0,dpr,0,0);ctx.clearRect(0,0,W,H);const R=Math.min(W,H)*0.42,cx=W/2,cy=H/2;const Q=P.map(rot);
ctx.lineWidth=0.6;for(const [i,j] of E){const z=(Q[i][2]+Q[j][2])/2;ctx.strokeStyle='rgba(200,210,255,'+(0.05+0.22*(z+1)/2)+')';ctx.beginPath();ctx.moveTo(cx+Q[i][0]*R,cy-Q[i][1]*R);ctx.lineTo(cx+Q[j][0]*R,cy-Q[j][1]*R);ctx.stroke()}
for(const q of Q){const z=(q[2]+1)/2;ctx.fillStyle='rgba(255,255,255,'+(0.15+0.85*z)+')';ctx.beginPath();ctx.arc(cx+q[0]*R,cy-q[1]*R,0.6+1.4*z,0,7);ctx.fill()}
const a1=rot(A),b1=rot(B);const pts=[];for(let k=0;k<=40;k++){const t=k/40;let x=a1[0]*(1-t)+b1[0]*t,y=a1[1]*(1-t)+b1[1]*t,z=a1[2]*(1-t)+b1[2]*t;const l=Math.hypot(x,y,z)||1,h=1+0.25*Math.sin(Math.PI*t);pts.push([cx+x/l*h*R,cy-y/l*h*R])}
const n=Math.max(2,Math.min(41,Math.floor(prog*40)));const gr=ctx.createLinearGradient(pts[0][0],pts[0][1],pts[40][0],pts[40][1]);gr.addColorStop(0,'#FF4FA3');gr.addColorStop(1,'#5B8CFF');ctx.strokeStyle=gr;ctx.lineWidth=2.2;ctx.beginPath();ctx.moveTo(pts[0][0],pts[0][1]);for(let k=1;k<n;k++)ctx.lineTo(pts[k][0],pts[k][1]);ctx.stroke();
for(const [p,c] of [[pts[0],'#FF4FA3'],[pts[n-1],'#5B8CFF']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(p[0],p[1],4,0,7);ctx.fill();ctx.strokeStyle='rgba(255,255,255,.9)';ctx.lineWidth=1.5;ctx.stroke()}
…