PageSourceSearch

https://ltvx.ai/assets/silk-ribbon-Dpy_iBxs.js

js ltvx.ai collected 2026-10-04 22:02:00 UTC 6,503 bytes, 118 lines download raw bytes

1import{r as a,j as l,C as h,d,f as c,h as v}from"./three-DGSc4TtV.js";const g=-.28,m=-1.3,p=1.75,b=1.15,w=.65,C=.5,T=[{colorT:.5,rOff:0,halfW:.11,tailAng:.55,alpha:.75,seed:3.1},{colorT:.28,rOff:.1,halfW:.09,tailAng:.62,alpha:.6,seed:9.7},{colorT:.75,rOff:-.1,halfW:.09,tailAng:.48,alpha:.65,seed:5.4},{colorT:.06,rOff:.2,halfW:.075,tailAng:.72,alpha:.5,seed:12.9},{colorT:.95,rOff:-.2,halfW:.065,tailAng:.42,alpha:.55,seed:7.3}],t=e=>e.toFixed(3),x=T.map(e=>`acc = strip(acc, r, ang, foldT, t, ${t(e.colorT)}, ${t(e.rOff)}, ${t(e.halfW)}, ${t(e.tailAng)}, ${t(e.alpha)}, ${t(e.seed)});`).join(`
2    `),A=`
3  varying vec2 vUv;
4
5  void main() {
6    vUv = uv;
7    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
8  }
9`,E=`
10  uniform float uTime;
11  uniform float uOpacity;
12  uniform float uAspect;
13  uniform vec3 uColorA;
14  uniform vec3 uColorB;
15  uniform vec3 uColorC;
16  uniform vec3 uColorD;
17  uniform vec3 uColorE;
18
19  varying vec2 vUv;
20
21  // Five stops blended in sequence, so the hue travels across the band — one
22  // continuous sweep through the accent family.
23  vec3 ramp(float t) {
24    t = clamp(t, 0.0, 1.0);
25    if (t < 0.25) return mix(uColorA, uColorB, t / 0.25);
26    if (t < 0.50) return mix(uColorB, uColorC, (t - 0.25) / 0.25);
27    if (t < 0.75) return mix(uColorC, uColorD, (t - 0.50) / 0.25);
28    return mix(uColorD, uColorE, (t - 0.75) / 0.25);
29  }
30
31  float hash(float n) {
32    return fract(sin(n) * 43758.5453123);
33  }
34
35  // 1D value noise: the streak texture only ever needs variation across one
36  // coordinate at a time, so nothing heavier is worth its cost here.
37  float vnoise(float x) {
38    float i = floor(x);
39    float fr = fract(x);
40    float u = fr * fr * (3.0 - 2.0 * fr);
41    return mix(hash(i), hash(i + 1.0), u);
42  }
43
44  // Front-to-back "over" compositing, premultiplied.
45  vec4 over(vec4 acc, vec3 rgb, float a) {
46    float w = (1.0 - acc.a) * a;
47    return vec4(acc.rgb + rgb * w, acc.a + w);
48  }
49
50  vec4 strip(
51    vec4 acc, float r, float ang, float foldT, float t,
52    float colorT, float rOff, float halfW, float tailAng, float amax, float seed
53  ) {
54    // Centreline radius: the shared arc, the strip's own offset — pulled
55    // inward at the fold so the strips gather — and a slow breathing sag.
56    float centre = ${t(p)} + rOff * (1.0 - 0.35 * foldT)
57      + 0.05 * sin(ang * 2.6 - t * 0.6 + seed);
58    // Strips thicken a little through the fold, like cloth seen edge-on.
59    float w = halfW * (1.0 + 0.35 * foldT);
60    float v = (r - centre) / w;
61    if (abs(v) >= 1.0) return acc;
62
63    // Soft airbrush profile — the strips have no hard edge, their overlaps do
64    // the drawing.
65    float env = 1.0 - smoothstep(0.2, 1.0, abs(v));
66
67    // Streaks running along the strip. Lines of constant q follow the arc, so
68    // they are the brush fibres; the waver bends them slightly against the
69    // flow so they read painted rather than ruled.
70    float q = v * 20.0 + seed * 19.0;
71    q += 2.0 * vnoise(ang * 1.6 + seed * 4.7) - 1.0;
72    float n = 0.65 * vnoise(q * 0.5) + 0.35 * vnoise(q * 1.7 + seed);
73    float fib = 0.5 + 0.5 * sin(q * 2.4);
74
75    // A faint brightness wave sliding left-to-right along the drape — the
76    // only fast motion, and barely-there on purpose.
77    float flow = 0.92 + 0.08 * sin(ang * 4.0 + t * 1.4 + q * 0.12);
78
79    // The tail fades out on the way down the fall, before the frame edge.
80    float tail = smoothstep(tailAng, tailAng + 0.4, ang);
81
82    float a = amax * env * (0.45 + 0.55 * n) * (0.88 + 0.12 * fib) * tail * flow;
83
84    // Colour drifts a little across the width and along the run, so each
85    // strip shades into its neighbours instead of printing flat.
86    vec3 rgb = ramp(colorT + 0.10 * v + 0.06 * sin(ang * 1.2 + seed - t * 0.25));
87    // Pale streaks toward each strip's crown: the silk sheen, strongest in
88    // the fold where the cloth turns through the light — and on the light
89    // theme what keeps the band from clogging into solid colour.
90    rgb = mix(rgb, vec3(1.0), (0.20 + 0.25 * foldT) * env * env * n);
91
92    return over(acc, rgb, a);
93  }
94
95  void main() {
96    vec2 p = vUv - 0.5;
97    p.x *= uAspect;
98
99    vec2 pivot = vec2(uAspect * ${t(g)}, ${t(m)});
100    vec2 d = p - pivot;
101    float r = length(d);
102    float ang = atan(d.y, d.x);
103    float foldT = 1.0 - smoothstep(${t(w)}, ${t(b)}, ang);
104    float t = uTime;
105
106    vec4 acc = vec4(0.0);
107    ${x}
108
109    if (acc.a < 0.004) discard;
110
111    vec3 rgb = acc.rgb / acc.a;
112    // A hair of dither: the profiles are wide and soft, which bands visibly
113    // on 8-bit output without it.
114    rgb += (hash(dot(gl_FragCoord.xy, vec2(0.754, 0.569))) - 0.5) / 25
1145.0;
115
116    gl_FragColor = vec4(rgb, acc.a * uOpacity);
117  }
118`,y={a:"#bae6fd",b:"#38bdf8",c:"#22d3ee",d:"#0891b2",e:"#2dd4bf",opacity:.95},O={a:"#0ea5e9",b:"#22d3ee",c:"#06b6d4",d:"#0e7490",e:"#14b8a6",opacity:.8};function S({palette:e,reduceMotion:f}){const{viewport:n}=d(),s=a.useRef(null),u=a.useRef(0),o=a.useMemo(()=>({uTime:{value:0},uOpacity:{value:e.opacity},uAspect:{value:1},uColorA:{value:new c(e.a)},uColorB:{value:new c(e.b)},uColorC:{value:new c(e.c)},uColorD:{value:new c(e.d)},uColorE:{value:new c(e.e)}}),[]);return a.useEffect(()=>{o.uColorA.value.set(e.a),o.uColorB.value.set(e.b),o.uColorC.value.set(e.c),o.uColorD.value.set(e.d),o.uColorE.value.set(e.e),o.uOpacity.value=e.opacity},[e,o]),v((i,r)=>{s.current&&(s.current.uniforms.uAspect.value=n.width/n.height,!f&&(u.current+=r*C,s.current.uniforms.uTime.value=u.current))}),l.jsxs("mesh",{children:[l.jsx("planeGeometry",{args:[n.width,n.height,1,1]}),l.jsx("shaderMaterial",{ref:s,uniforms:o,vertexShader:A,fragmentShader:E,transparent:!0,depthWrite:!1,toneMapped:!1})]})}function R({className:e}){const[f,n]=a.useState(()=>document.documentElement.classList.contains("dark")),[s,u]=a.useState(()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches);a.useEffect(()=>{const i=()=>n(document.documentElement.classList.contains("dark")),r=new MutationObserver(i);return r.observe(document.documentElement,{attributes:!0,attributeFilter:["class"]}),()=>r.disconnect()},[]),a.useEffect(()=>{const i=window.matchMedia("(prefers-reduced-motion: reduce)"),r=()=>u(i.matches);return i.addEventListener("change",r),()=>i.removeEventListener("change",r)},[]);const o=f?O:y;return l.jsx("div",{className:e,"aria-hidden":"true",children:l.jsx(h,{dpr:[1,1.5],gl:{antialias:!0,alpha:!0},style:{background:"transparent"},children:l.jsx(S,{palette:o,reduceMotion:s})})})}export{R as SilkRibbon};

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.