PageSourceSearch

https://sol.vin/js/cube.js

js sol.vin collected 2026-10-09 21:58:28 UTC 9,881 bytes, 324 lines download raw bytes

1(function() {
2  function initCubeApp() {
3    try {
4      const container = document.getElementById('header-cube-app');
5      if (!container || container.dataset.initialized) return;
6      container.dataset.initialized = 'true';
7
8      const svgNS = 'http://www.w3.org/2000/svg';
9      const svg = document.createElementNS(svgNS, 'svg');
10      svg.setAttribute('class', 'cube-svg');
11      svg.setAttribute('width', '64');
12      svg.setAttribute('height', '64');
13      svg.setAttribute('viewBox', '0 0 64 64');
14
15      // 3D Cube Vertices centered at origin
16      const s = 14;
17      const baseVertices = [
18        [-s, -s, -s],
19        [ s, -s, -s],
20        [ s,  s, -s],
21        [-s,  s, -s],
22        [-s, -s,  s],
23        [ s, -s,  s],
24        [ s,  s,  s],
25        [-s,  s,  s]
26      ];
27
28      const edges = [
29        [0,1], [1,2], [2,3], [3,0],
30        [4,5], [5,6], [6,7], [7,4],
31        [0,4], [1,5], [2,6], [3,7]
32      ];
33
34      const lineElems = edges.map(() => {
35        const line = document.createElementNS(svgNS, 'line');
36        line.setAttribute('class', 'cube-edge');
37        svg.appendChild(line);
38        return line;
39      });
40
41      container.appendChild(svg);
42
43      // Target 45, 45, 45 degree rotation matrix
44      const rad45 = Math.PI / 4;
45      function matMult3x3(A, B) {
46        const C = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
47        for (let i = 0; i < 3; i++) {
48          for (let j = 0; j < 3; j++) {
49            C[i][j] = A[i][0] * B[0][j] + A[i][1] * B[1][j] + A[i][2] * B[2][j];
50          }
51        }
52        return C;
53      }
54
55      const Rx45 = [
56        [1, 0, 0],
57        [0, Math.cos(rad45), -Math.sin(rad45)],
58        [0, Math.sin(rad45), Math.cos(rad45)]
59      ];
60      const Ry45 = [
61        [Math.cos(rad45), 0, Math.sin(rad45)],
62        [0, 1, 0],
63        [-Math.sin(rad45), 0, Math.cos(rad45)]
64      ];
65      const Rz45 = [
66        [Math.cos(rad45), -Math.sin(rad45), 0],
67        [Math.sin(rad45), Math.cos(rad45), 0],
68        [0, 0, 1]
69      ];
70      const targetR = matMult3x3(Rz45, matMult3x3(Ry45, Rx45));
71
72      // Initial orientation set directly to the 45 degree target position
73      let R = targetR;
74
75      const MIN_SPEED = 0.008;
76      const MAX_SPEED = 0.18;
77      const FRICTION = 0.985;
78      const HOLD_DURATION = 5000; // 5 seconds still hold time
79      const RAMP_DURATION = 1500; // 1.5 seconds smooth drift ramp up
80
81      function getRandomDirection() {
82        let rx = (Math.random() - 0.5) * 2;
83        let ry = (Math.random() - 0.5) * 2;
84        let rz = (Math.random() - 0.5) * 2;
85        if (Math.abs(rx) < 0.2) rx += (rx >= 0 ? 0.4 : -0.4);
86        if (Math.abs(ry) < 0.2) ry += (ry >= 0 ? 0.4 : -0.4);
87        const len = Math.hypot(rx, ry, rz) || 1;
88        return [rx / len, ry / len, rz / len];
89      }
90
91      let vx = 0;
92      let vy = 0;
93      let vz = 0;
94
95      // Interaction & Animation States
96      let prevMousePos = null;
97      let centeringTimer = null;
98      let isCentering = false;
99      let isDriftRamping = false;
100      let driftRampStartTime = 0;
101      let startDriftVel = [0, 0, 0];
102      let targetDriftVel = [0, 0, 0];
103
104      function startDrifting() {
105        const dir = getRandomDirection();
106        const targetSpeed = MIN_SPEED * 1.5;
107        targetDriftVel = [
108          dir[0] * targetSpeed,
109          dir[1] * targetSpeed,
110          dir[2] * targetSpeed
111        ];
112        startDriftVel = [vx, vy, vz];
113        isDriftRamping = true;
114        driftRampStartTime = performance.now();
115      }
116
117      function triggerCenter() {
118        if (centeringTimer) clearTimeout(centeringTimer);
119        isCentering = true;
120        isDriftRamping = false;
121        vx = 0;
122        vy = 0;
123        vz = 0;
124        centeringTimer = setTimeout(() => {
125          isCentering = false;
126          centeringTimer = null;
127          startDrifting();
128        }, HOLD_DURATION);
129      }
130
131      function triggerFastSpin() {
132        if (centeringTimer) {
133          clearTimeout(centeringTimer);
134          centeringTimer = null;
135        }
136        isCentering = false;
137        isDriftRamping = false;
138        const dir = getRandomDirection();
139        vx = dir[0] * MAX_SPEED;
140        vy = dir[1] * MAX_SPEED;
141        vz = dir[2] * MAX_SPEED;
142      }
143
144      container.style.cursor = 'pointer';
145
146      // Start initial state held still at 45 degree angle for 5 seconds
147      triggerCenter();
148
149      container.addEventListener('click', (e) => {
150        if (e.button === 0) {
151          triggerFastSpin();
152        }
153      });
154
155      container.addEventListener('contextmenu', (e) => {
156        e.preventDefault();
157        triggerCenter();
158      });
159
160      container.addEventListener('mouseenter', (e) => {
161        prevMousePos = { x: e.clientX, y: e.clientY };
162      });
163
164      container.addEventListener('mouseleave', () => {
165        prevMousePos = null;
166      });
167
168      container.addEventListener('mousemove', (e) => {
169        if (isCentering) return;
170        if (!prevMousePos) {
171          prevMousePos = { x: e.clientX, y: e.clientY };
172          return;
173        }
174        const dx = e.clientX - prevMousePos.x;
175        const dy = e.clientY - prevMousePos.y;
176        prevMousePos = { x: e.clientX, y: e.clientY };
177
178        const deltaDist = Math.hypot(dx, dy);
179        if (deltaDist > 0) {
180          if (isDriftRamping) {
181            isDriftRamping = false;
182          }
183          vy += dx * 0.0025;
184          vx -= dy * 0.0025;
185          vz += (dx - dy) * 0.001;
186
187          const currentSpeed = Math.hypot(vx, vy, vz);
188          if (currentSpeed > MAX_SPEED) {
189            const scale = MAX_SPEED / currentSpeed;
190            vx *= scale;
191            vy *= scale;
192            vz *= scale;
193          }
194        }
195      });
196
197      function transpose3x3(M) {
198        return [
199          [M[0][0], M[1][0], M[2][0]],
200          [M[0][1], M[1][1], M[2][1]],
201          [M[0][2], M[1][2], M[2][2]]
202        ];
203      }
204
205      function animate() {
206        if (isCentering) {
207          const R_T = transpose3x3(R);
208          const R_rel = matMult3x3(targetR, R_T);
209          const trace = R_rel[0][0] + R_rel[1][1] + R_rel[2][2];
210          const cosTheta = Math.min(1, Math.max(-1, (trace - 1) / 2));
211          const theta = Math.acos(cosTheta);
212
213          if (theta < 0.001) {
214            R = targetR;
215            vx = 0;
216            vy = 0;
217            vz = 0;
218          } else {
219            let rx = R_rel[2][1] - R_rel[1][2];
220            let ry = R_rel[0][2] - R_rel[2][0];
221            let rz = R_rel[1][0] - R_rel[0][1];
222            let len = Math.hypot(rx, ry, rz);
223            if (len < 1e-6) {
224              rx = 1; ry = 0; rz = 0; len = 1;
225            }
226            const w = Math.min(0.2, Math.max(0.01, theta * 0.15));
227            vx = (rx / len) * w;
228            vy = (ry / len) * w;
229            vz = (rz / len) * w;
230          }
231        } else if (isDriftRamping) {
232          const elapsed = performance.now() - driftRampStartTime;
233          const t = Math.min(1, elapsed / RAMP_DURATION);
234          // Smoothstep interpolation t * t * (3 - 2 * t)
235          const easeT = t * t * (3 - 2 * t);
236          vx = startDriftVel[0] + (targetDriftVel[0] - startDriftVel[0]) * easeT;
237          vy = startDriftVel[1] + (targetDriftVel[1] - startDriftVel[1]) * easeT;
238          vz = startDriftVel[2] + (targetDriftVel[2] - startDriftVel[2]) * easeT;
239          if (t >= 1) {
240            isDriftRamping = false;
241          }
242        } else {
243          vx *= FRICTION;
244          vy *= FRICTION;
245          vz *= FRICTION;
246
247          let speed = Math.hypot(vx, vy, vz);
248
249          if (speed < MIN_SPEED) {
250            if (speed < 0.0001) {
251              const dir = getRandomDirection();
252              vx = dir[0] * MIN_SPEED;
253              vy = dir[1] * MIN_SPEED;
254              vz = dir[2] * MIN_SPEED;
255            } else {
256              const scale = MIN_SPEED / speed;
257              vx *= scale;
258              vy *= scale;
259              vz *= scale;
260            }
261            speed = MIN_SPEED;
262          } else if (speed > MAX_SPEED) {
263            const scale = MAX_SPEED / speed;
264            vx *= scale;
265            vy *= scale;
266            vz *= scale;
267            speed = MAX_SPEED;
268          }
269        }
270
271        const speed = Math.hypot(vx, vy, vz);
272        if (speed > 0.00001) {
273          const ax = vx / speed, ay = vy / speed, az = vz / speed;
274          const cos = Math.cos(speed), sin = Math.sin(speed), c1 = 1 - cos;
275
276          const dR = [
277            [cos + ax*ax*c1,      ax*ay*c1 - az*sin, ax*az*c1 + ay*sin],
278            [ay*ax*c1 + az*sin, cos + ay*ay*c1,      ay*az*c1 - ax*sin],
279            [az*ax*c1 - ay*sin, az*ay*c1 + ax*sin, cos + az*az*c1]
280          ];
281
282          const nextR = [
283            [0, 0, 0],
284            [0, 0, 0],
285            [0, 0, 0]
286          ];
287          for (let i = 0; i < 3; i++) {
288            for (let j = 0; j < 3; j++) {
289              nextR[i][j] = dR[i][0] * R[0][j] + dR[i][1] * R[1][j] + dR[i][2] * R[2][j];
290            }
291          }
292          R = nextR;
293        }
294
295        const proj = baseVertices.map(v => [
296          32 + (R[0][0]*v[0] + R[0][1]*v[1] + R[0][2]*v[2]),
297          32 + (R[1][0]*v[0] + R[1][1]*v[1] + R[1][2]*v[2])
298        ]);
299
300        edges.forEach((edge, idx) => {
301          const p1 = proj[edge[0]];
302          const p2 = proj[edge[1]];
303          lineElems[idx].setAttribute('x1', p1[0].toFixed(2));
304          lineElems[idx].setAttribute('y1', p1[1].toFixed(2));
305          lineElems[idx].setAttribute('x2', p2[0].toFixed(2));
306          lineElems[idx].setAttribute('y2', p2[1].toFixed(2));
307        });
308
309        requestAnimationFrame(animate);
310      }
311
312      requestAnimationFrame(animate);
313    } catch(err) {
314      console.error("Cube init error:", err);
315    }
316  }
317
318  if (document.readyState === 'loading') {
319    document.addEventListener('DOMContentLoaded', initCubeApp);
320  }
321  initCubeApp();
322  setTimeout(initCubeApp, 100);
323  setTimeout(initCubeApp, 500);
324})();

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.