PageSourceSearch

https://scalz.ai/luminous/preview/flights.js?v=orbital-19

js scalz.ai collected 2026-10-05 12:37:15 UTC 8,665 bytes, 147 lines download raw bytes

1(() => {
2  "use strict";
3  const environment = document.querySelector(".hero-environment");
4  const hero = document.querySelector("#hero");
5  if (!environment || !hero) return;
6  const canvas = document.createElement("canvas");
7  canvas.className = "flight-field"; canvas.setAttribute("aria-hidden", "true");
8  environment.append(canvas);
9  const ctx = canvas.getContext("2d", { alpha: true });
10  if (!ctx) return;
11  const reduced = matchMedia("(prefers-reduced-motion: reduce)");
12  let enabled = !reduced.matches && !document.documentElement.classList.contains("preview-effects-off");
13  let visible = true, raf = 0, previous = 0, time = 0, painted = 0;
14  let width = 1, height = 1, ratio = 1, worldScale = 1, offsetX = 0, offsetY = 0;
15  const particles = [], flights = [], rings = [], plumes = [];
16  let flightCount = 0, nextFlight = 7800;
17  const ridge = [[0,560],[200,582],[420,592],[560,574],[635,550],[745,578],[834,575],[920,583],[1110,586],[1240,566],[1330,547],[1424,507],[1490,548],[1536,564]];
18  const rand = (a,b) => a + Math.random() * (b-a);
19  function terrain(x) {
20    for (let i=1;i<ridge.length;i++) if (x <= ridge[i][0]) {
21      const a=ridge[i-1],b=ridge[i];return a[1]+(b[1]-a[1])*(x-a[0])/(b[0]-a[0]);
22    }
23    return 580;
24  }
25  const smoke = document.createElement("canvas"); smoke.width=64;smoke.height=64;
26  const sc=smoke.getContext("2d");
27  const gradient=sc.createRadialGradient(32,32,1,32,32,31);
28  gradient.addColorStop(0,"rgba(245,247,240,.66)");gradient.addColorStop(.35,"rgba(221,234,228,.4)");gradient.addColorStop(1,"rgba(217,231,226,0)");
29  sc.fillStyle=gradient;sc.fillRect(0,0,64,64);
30
31  function spawn(kind, x, elapsed=0, size=rand(.55,1.05)) {
32    const landing=kind==="landing";
33    const ground=terrain(x)+8-(1-size)*12;
34    const start=landing?{x:x+rand(70,150),y:rand(-90,40)}:{x,y:ground};
35    const end=landing?{x,y:ground-3}:{x:x+rand(85,170),y:-35};
36    const plume={size,points:[]};plumes.push(plume);
37    flights.push({ kind, start, end, ground, size, plume, born:time-elapsed, duration:landing?rand(19500,25000):rand(18500,27000), lastEmit:-1000, entry:false });
38    flightCount++;
39  }
40  function position(f,p) {
41    const t=f.kind==="landing"?1-Math.pow(1-p,2.45):Math.pow(p,1.4);
42    const a=f.start,b=f.end;
43    if (f.kind==="landing") {
44      const curve=Math.sin(Math.PI*t)*46;
45      return {x:a.x+(b.x-a.x)*t+curve,y:a.y+(b.y-a.y)*t};
46    }
47    const curve=Math.pow(Math.max(0,(t-.53)/.47),1.9);
48    return {x:a.x+(b.x-a.x)*curve,y:a.y+(b.y-a.y)*t};
49  }
50  function particle(x,y,size,vx,vy,life,opacity=.35) {
51    if(particles.length>=720)particles.shift();
52    particles.push({x,y,size,vx,vy,life,opacity,born:time,twist:rand(0,Math.PI*2)});
53  }
54  function entry(f,p) {
55    f.entry=true;rings.push({x:p.x,y:p.y,born:time,size:f.size});
56    for(let i=0;i<42;i++) {
57      const a=i/42*Math.PI*2;
58      particle(p.x+Math.cos(a)*7,p.y+Math.sin(a)*3,rand(3,7)*f.size,Math.cos(a)*rand(18,35),Math.sin(a)*rand(5,15),rand(3500,6500),.42);
59    }
60    for(const puff of particles){const d=Math.hypot(puff.x-p.x,puff.y-p.y);if(d<90&&d>2){puff.vx+=(puff.x-p.x)/d*15;puff.vy+=(puff.y-p.y)/d*8;}}
61    window.dispatchEvent(new CustomEvent("scalz:atmosphere-entry",{detail:{x:p.x/1536,y:p.y/1024}}));
62  }
63  function glow(x,y,size,intensity) {
64    const radius=9*size*intensity;
65    const g=ctx.createRadialGradient(x,y,0,x,y,radius);
66    g.addColorStop(0,"rgba(255,255,233,.95)");g.addColorStop(.13,"rgba(255,239,182,.82)");g.addColorStop(.4,"rgba(255,174,92,.3)");g.addColorStop(1,"rgba(255,148,70,0)");
67    ctx.fillStyle=g;ctx.beginPath();ctx.arc(x,y,radius,0,Math.PI*2);ctx.fill();
68  }
69  function paint(dt) {
70    ctx.setTransform(1,0,0,1,0,0);ctx.clearRect(0,0,canvas.width,canvas.height);
71    ctx.setTransform(ratio*worldScale,0,0,ratio*worldScale,offsetX*ratio,offsetY*ratio);
72    ctx.save();ctx.beginPath();ctx.moveTo(0,-500);ctx.lineTo(1536,-500);
73    [...ridge].reverse().forEach(p=>ctx.lineTo(p[0],p[1]));ctx.closePath();ctx.clip();
74    // Soft overlapping volumes join the entire exhaust path; no sharp center line.
75    ctx.lineCap='round';ctx.lineJoin='round';
76    for(let k=plumes.length-1;k>=0;k--){
77      const plume=plumes[k];plume.points=plume.points.filter(p=>time-p.born<34000);
78      if(!plume.points.length){if(!flights.some(f=>f.plume===plume))plumes.splice(k,1);continue;}
79      const points=plume.points;
80      for(let i=0;i<points.length-1;i+=12){
81        const segment=points.slice(i,Math.min(points.length,i+14));
82        const age=(time-segment[0].born)/34000,fade=Math.pow(1-age,1.7),spread=(8+age*30)*plume.size;
83        for(let pass=0;pass<2;pass++){
84          ctx.strokeStyle=pass?`rgba(242,246,237,${.21*fade})`:`rgba(154,181,178,${.12*fade})`;
85          ctx.lineWidth=spread*(pass?1:1.8);ctx.filter=`blur(${pass?2.3:3.8}px)`;ctx.beginPath();
86          segment.forEach((p,j)=>{const seconds=(time-p.born)/1000;const x=p.x+seconds*.36+Math.sin(seconds*.42+p.y*.035)*seconds*.18,y=p.y-seconds*.2;if(j===0)ctx.moveTo(x,y);else ctx.lineTo(x,y);});ctx.stroke();
87        }
88      }
89    }
90    ctx.filter='none';
91    for(let i=particles.length-1;i>=0;i--) {
92      const p=particles[i],age=(time-p.born)/p.life;
93      if(age>=1){particles.splice(i,1);continue;}
94      p.x+=p.vx*dt;p.y+=p.vy*dt;p.vx*=.998;p.vy*=.998;
95      const radius=p.size*(1+age*4.5);
96      ctx.globalAlpha=p.opacity*Math.pow(1-age,1.25)*Math.min(1,age*12+.22);
97      ctx.drawImage(smoke,p.x-radius,p.y-radius,radius*2,radius*2);
98    }
99    ctx.globalAlpha=1;
100    for(let i=rings.length-1;i>=0;i--) {
101      const ring=rings[i],age=(time-ring.born)/3200;
102      if(age>=1){rings.splice(i,1);continue;}
103      const radius=(12+age*150)*ring.size;
104      ctx.strokeStyle=`rgba(232,250,244,${(1-age)*.27})`;ctx.lineWidth=2.4*(1-age);
105      ctx.beginPath();ctx.ellipse(ring.x,ring.y,radius,radius*.33,-.12,0,Math.PI*2);ctx.stroke();
106    }
107    for(let i=flights.length-1;i>=0;i--) {
108      const f=flights[i],p=Math.min(1,(time-f.born)/f.duration),point=position(f,p);
109      if(p>=1){flights.splice(i,1);continue;}
110      const landing=f.kind==="landing";
111      if(landing&&!f.entry&&point.y>165)entry(f,point);
112      const altitude=Math.max(0,f.ground-point.y);
113      const braking=landing?Math.max(0,1-altitude/130):0;
114      const pulse=.65+.35*Math.pow(Math.sin(time*.009),2);
115      const intensity=landing?1+braking*1.9*pulse:1.05+Math.min(.35,p);
116      if(time-f.lastEmit>42) {
117        const old=position(f,Math.max(0,p-.006));
118        const dx=point.x-old.x,dy=point.y-old.y,d=Math.hypot(dx,dy)||1;
119        f.plume.points.push({x:point.x,y:point.y,born:time});
120        particle(point.x+rand(-1,1),point.y+rand(-1,1),rand(5,8)*f.size,rand(-.8,.8)-dx/d*.7,rand(-.7,.7)-dy/d*.7,rand(24000,34000),.25*f.size);
121        if(braking>.2)particle(point.x,point.y+4,rand(2.5,4.5)*f.size,rand(-10,10),rand(11,24),rand(6500,11000),.5*braking);
122        f.lastEmit=time;
123      }
124      glow(point.x,point.y,f.size,intensity);
125    }
126    ctx.restore();canvas.dataset.activeFlights=String(flights.length);canvas.dataset.particles=String(particles.length);canvas.dataset.plumes=String(plumes.length);canvas.dataset.launchZone='open-valley-690-855';
127  }
128  function frame(now) {
129    if(!enabled||!visible||document.hidden||reduced.matches){raf=0;previous=0;return;}
130    const dt=previous?Math.min(100,now-previous):0;time+=dt;previous=now;
131    if(time>nextFlight&&flights.length<3){spawn(flightCount%2?"landing":"launch",rand(690,855));nextFlight=time+rand(8200,12500);}
132    if(now-painted>32){paint(Math.min(100,now-painted)/1000);painted=now;}
133    raf=requestAnimationFrame(frame);
134  }
135  function resize() {
136    const r=hero.getBoundingClientRect();width=r.width;height=r.height;ratio=Math.min(devicePixelRatio||1,1.25,1800/Math.max(width,height));
137    canvas.width=Math.round(width*ratio);canvas.height=Math.round(height*ratio);worldScale=Math.max(width/1536,height/1024);offsetX=(width-1536*worldScale)/2;offsetY=(height-1024*worldScale)/2;
138  }
139  function sync(){if(raf)cancelAnimationFrame(raf);raf=0;previous=0;if(enabled&&visible&&!document.hidden&&!reduced.matches)raf=requestAnimationFrame(frame);}
140  spawn("launch",760,0,.85);spawn("landing",835,0,.55);nextFlight=11000;
141  new ResizeObserver(resize).observe(hero);
142  new IntersectionObserver(entries=>{visible=entries[0].isIntersecting;sync();},{threshold:.03}).observe(hero);
143  window.addEventListener("scalz:preview-effects",e=>{enabled=Boolean(e.detail.enabled);sync();});
144  document.addEventListener("visibilitychange",sync);
145  reduced.addEventListener("change",()=>{enabled=!reduced.matches&&!document.documentElement.classList.contains("preview-effects-off");sync();});
146  resize();sync();
147})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.