PageSourceSearch

https://orionofficial.info/assets/sayfa.js

js orionofficial.info collected 2026-10-02 01:57:14 UTC 44,568 bytes, 1,020 lines download raw bytes

1/* ORION tanıtım sitesi — ortak sayfa betiği.
2   index.html ve ürün sayfaları paylaşır. Sayfaya özel parçalar
3   (sekmeler, senaryolar, çerçeve içi hareket, akış şeridi) ilgili
4   eleman yoksa kendiliğinden atlanıyor. */
5(function () {
6  "use strict";
7  var reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;
8  if (!window.gsap) { document.documentElement.className = "no-js"; return; }
9
10  /* ── ilerleme çubuğu ── */
11  var prog = document.getElementById("prog");
12  addEventListener("scroll", function () {
13    var h = document.documentElement.scrollHeight - innerHeight;
14    prog.style.width = (h > 0 ? (scrollY / h) * 100 : 0) + "%";
15  }, { passive: true });
16
17
18  /* menüdeki ışık imleci izlesin */
19  var navIn = document.querySelector(".nav-in");
20  if (navIn) {
21    navIn.addEventListener("pointermove", function (e) {
22      var r = navIn.getBoundingClientRect();
23      navIn.style.setProperty("--mx", (e.clientX - r.left) + "px");
24      navIn.style.setProperty("--my", (e.clientY - r.top) + "px");
25    });
26  }
27
28
29  /* ── sekme başlığı: "ORION" sabit, sağı dönüyor ──────────────────
30     Cümleler sözlükte ZATEN olan anahtarlardan seçildi; böylece dil
31     değişince başlık da kendiliğinden çevriliyor, ayrıca çeviri
32     yazmak gerekmiyor. */
33  /* ⚠️ YALNIZCA ANA SAYFADA. Bu blok eskiden HER sayfada calisiyordu ve
34     document.title'i eziyordu: sekiz sayfanin sekizi de JS calistiktan
35     sonra "ORION — Yonetilen yayin." oluyordu (olculdu 2026-08-17).
36
37     Googlebot JavaScript'i CALISTIRIYOR. Yani arama motoru sekiz ayri
38     sayfayi ayni, sayfayla ilgisiz basligla goruyordu — baslik hem en
39     guclu sayfa-ici siralama sinyali hem de sonuc listesinde gorunen
40     metin. Urun ve arac sayfalarinin kendi basliklari hic sayilmiyordu.
41
42     Ic sayfalarda bayrak false kaldigi icin i18n baslığı devralir ve
43     sayfanin KENDI basligini dile cevirir (bkz. i18n.js, ic sayfa dali). */
44  var ANA_SAYFA = location.pathname === "/" || location.pathname === "/index";
45  if (ANA_SAYFA) {
46    var BASLIKLAR = [
47      "Kanıtlanmış moderasyon.",
48      "Yönetilen yayın.",
49      "Sohbeti kim izliyor?",
50      "Yedi araç."
51    ];
52    window.__orionTitleAnim = true;   /* i18n başlığı ezmesin */
53    (function () {
54      var i = 0;
55      function tik() {
56        var T = window.ORION_T || function (x) { return x; };
57        document.title = "ORION — " + T(BASLIKLAR[i]);
58        i = (i + 1) % BASLIKLAR.length;
59      }
60      tik();
61      if (!reduced) setInterval(tik, 3200);
62    })();
63  }
64
65  /* ── menü geçişleri ───────────────────────────────────────────────
66     Üç parça: (1) altta kayan gösterge, (2) tıklayınca yumuşatılmış
67     kaydırma, (3) varılan bölümün başlığının yeniden açılması.
68
69     ⚠️ GSAP'ın ScrollTo eklentisi YOK ve gerekmiyor: bir vekil nesnenin
70     `y` değerini tween'leyip her karede scrollTo çağırmak aynı işi
71     görüyor, fazladan dosya yüklemiyoruz.
72     ⚠️ CSS'teki `scroll-behavior:smooth` bu sırada KAPATILMALI, yoksa
73     her scrollTo çağrısı kendi başına yumuşamaya çalışıp titriyor. */
74  var navLinks = [].slice.call(document.querySelectorAll(".nav-links a"));
75  var navInd = document.getElementById("navInd");
76  var NAV_H = 92;                       /* yüzen menünün kapladığı yükseklik */
77  var scrolling = false;
78
79  function sectionOf(a) {
80    var id = (a.getAttribute("href") || "").slice(1);
81    return id ? document.getElementById(id) : null;
82  }
83
84  function moveInd(a) {
85    if (!navInd) return;
86    if (!a) { navInd.style.opacity = 0; return; }
87    var p = a.parentElement.getBoundingClientRect(), r = a.getBoundingClientRect();
88    navInd.style.opacity = 1;
89    if (window.gsap && !reduced) {
90      gsap.to(navInd, { left: r.left - p.left, width: r.width,
91                        duration: .45, ease: "power3.out" });
92    } else {
93      navInd.style.left = (r.left - p.left) + "px";
94      navInd.style.width = r.width + "px";
95    }
96  }
97
98  function syncNav() {
99    if (scrolling) return;             /* tıklama sırasında karışmasın */
100    var mid = innerHeight * 0.42, active = null;
101    navLinks.forEach(function (a) {
102      var el = sectionOf(a); if (!el) return;
103      var r = el.getBoundingClientRect();
104      if (r.top <= mid && r.bottom >= mid) active = a;
105    });
106    navLinks.forEach(function (a) { a.classList.toggle("on", a === active); });
107    moveInd(active);
108  }
109  addEventListener("scroll", syncNav, { passive: true });
110  addEventListener("resize", syncNav);
111
112  /* varılan bölümün başlığını bir kez daha aç — geldiğin yer belli olsun */
113  function replayHead(el) {
114    if (!el || !window.gsap || reduced) return;
115    var lines = el.querySelectorAll("h2 .ln > span");
116    if (!lines.length) return;
117    gsap.fromTo(lines,
118      { yPercent: 135, filter: "blur(7px)" },
119      { yPercent: 0, filter: "blur(0px)", duration: .8, stagger: .07, ease: "power3.out" });
120  }
121
122  function goTo(el, link) {
123    if (!el) return;
124    var y = Math.max(0, el.getBoundingClientRect().top + scrollY - NAV_H);
125    navLinks.forEach(function (a) { a.classList.toggle("on", a === link); });
126    moveInd(link);
127
128    if (!window.gsap || reduced) { scrollTo(0, y); replayHead(el); return; }
129
130    scrolling = true;
131    var o = { y: scrollY };
132    gsap.to(o, {
133      y: y, duration: Math.min(1.15, 0.35 + Math.abs(y - scrollY) / 2600),
134      ease: "power2.inOut",
135      onUpdate: function () { scrollTo(0, o.y); },
136      onComplete: function () { scrolling = false; replayHead(el); syncNav(); }
137    });
138  }
139
140  if (window.gsap && !reduced) document.documentElement.classList.add("js-scroll");
141
142  [].slice.call(document.querySelectorAll('a[href^="#"]')).forEach(function (a) {
143    var href = a.getAttribute("href");
144    if (!href || href === "#") return;
145    a.addEventListener("click", function (e) {
146      var el = document.getElementById(href.slice(1));
147      if (!el) return;
148      e.preventDefault();
149      goTo(el, navLinks.indexOf(a) > -1 ? a : null);
150      history.replaceState(null, "", href);
151    });
152  });
153
154  addEventListener("load", syncNav);
155  setTimeout(syncNav, 300);
156
157  if (!reduced) {
158    gsap.registerPlugin(ScrollTrigger);
159
160    /* ⚠️ Başlangıcı GSAP'a kurdur — CSS'teki translateY(%) GSAP tarafından
161       piksel olarak okunuyor, sonra yPercent:0 onu yerinde bırakıyor. */
162    gsap.set(".ln > span", { y: 0, yPercent: 135, filter: "blur(7px)" });
163    gsap.set(".fade", { opacity: 0, y: 18 });
164
165    document.querySelectorAll("h1, h2").forEach(function (h) {
166      var l = h.querySelectorAll(".ln > span");
167      if (!l.length) return;
168      gsap.to(l, {
169        yPercent: 0, filter: "blur(0px)", duration: 0.95, stagger: 0.08,
170        ease: "power3.out",
171        scrollTrigger: { trigger: h, start: "top 82%", once: true }
172      });
173    });
174
175    /* ⚠️ `clearProps` ŞART — yoksa hover/basma efektleri SESSİZCE ÖLÜR.
176       GSAP animasyon boyunca öğeye satır içi stil yazıyor ve `once: true`
177       olduğu için bitince orada bırakıyordu:
178
179           translate: none; rotate: none; scale: none;
180           transform: translate(0px, 0px);
181
182       Satır içi stil her stylesheet kuralını ezer. Sonuç: `.extbar:hover
183       {transform:translateY(-2px)}` gibi kurallar hiç çalışmıyordu — CDP ile
184       hover'ı zorlayıp ölçtüm, hiçbir şey olmuyordu. Yani sitenin kendi
185       hover efektleri `.fade` taşıyan her öğede ölüydü.
186
187       Animasyon bitince transform ailesini temizliyoruz; `opacity` satır içi
188       kalıyor (görünürlüğü o taşıyor). `.fade`in CSS'te transform'u yok, o
189       yüzden temizlemek öğeyi doğru yerinde bırakır. */
190    gsap.utils.toArray(".fade").forEach(function (el) {
191      gsap.to(el, {
192        opacity: 1, y: 0, duration: 0.8, ease: "power3.out",
193        clearProps: "transform,translate,rotate,scale",
194        scrollTrigger: { trigger: el, start: "top 88%", once: true }
195      });
196    });
197
198    /* sağ ray — kaydırdıkça aşama ilerliyor */
199    var rail = document.querySelectorAll(".rail div");
200    ["#sorun", "#panel", "#urunler"].forEach(function (sel, i) {
201      var t = document.querySelector(sel);
202      if (!t) return;
203      ScrollTrigger.create({
204        trigger: t, start: "top 60%", end: "bottom 40%",
205        onToggle: function (s) {
206          rail.forEach(function (d, j) { d.classList.toggle("on", s.isActive ? j === i : j === 0); });
207        }
208      });
209    });
210
211    /* panel görsellerine hafif parallax */
212    gsap.utils.toArray(".mock").forEach(function (img) {
213      gsap.fromTo(img, { yPercent: -1.6 }, {
214        yPercent: 1.6, ease: "none",
215        scrollTrigger: { trigger: img, start: "top bottom", end: "bottom top", scrub: true }
216      });
217    });
218  } else {
219    gsap.set(".ln > span", { yPercent: 0 });
220    gsap.set(".fade", { opacity: 1, y: 0 });
221  }
222
223
224
225
226  /* ── akış şeridi animasyonu ──────────────────────────────────────
227     Sinyal basamak basamak ilerliyor. Renk BEZEME DEĞİL, sıcaklık
228     eğrisi — her basamak kararın ne kadar sertleştiğini gösteriyor:
229
230       MESAJ     çelik   ham girdi, henüz hiçbir şeye karar verilmedi
231       KURAL     amber   tartılıyor
232       KARAR     turuncu karar sertleşiyor
233       MÜDAHALE  kızıl   keskin uç (paletteki --crimson zaten "müdahale"
234                         için ayrılmıştı; burada onun açık eşi
235                         --crimson-2 kullanılıyor, çünkü 12px mono
236                         yazıda --crimson 4.4:1 ile AA eşiğinin altında
237                         kalıyor — açık eşi 6.2:1)
238       KAYIT     mint    oturdu, yazıldı
239
240     ⚠️ Renkler burada, CSS'te değil: bağlayıcı çizgi iki komşu basamak
241     arasında GEÇİŞ yapıyor, yani her segmentin gradyanı kendi rengiyle
242     sonrakinin renginden kuruluyor. Tek yerde durmaları şart.
243     ⚠️ Yalnızca bölüm görünürken çalışıyor; sayfanın altındayken boşuna
244     kare harcamasın diye. */
245  var AKIS_RENK = ["#7C9CC4", "#E3B341", "#F08B3C", "#FF4D68", "#5FD49B"];
246  var AKIS_RGB  = ["124,156,196", "227,179,65", "240,139,60", "255,77,104", "95,212,155"];
247
248  var flow = document.getElementById("flow");
249  if (flow && window.gsap && !reduced) {
250    var steps = [].slice.call(flow.querySelectorAll(".step"));
251    var SON = steps.length - 1;
252    /* son basamaktan fazla basamak varsa renkler başa dönsün, undefined olmasın */
253    var renkAl = function (i) { return AKIS_RENK[i % AKIS_RENK.length]; };
254    var rgbAl  = function (i) { return AKIS_RGB[i % AKIS_RGB.length]; };
255
256    /* Her segment kendi renginden sonrakine geçiyor. */
257    steps.forEach(function (st, i) {
258      var fill = st.querySelector(".fill");
259      if (fill && i < SON) {
260        fill.style.backgroundImage = "linear-gradient(90deg,rgba(" + rgbAl(i) +
261          ",.9),rgba(" + rgbAl(i + 1) + ",.9))";
262      }
263    });
264
265    var tl = gsap.timeline({ repeat: -1, repeatDelay: 1.1, paused: true });
266    tl.set(steps.map(function (st) { return st.querySelector(".fill"); }), { scaleX: 0 })
267      .set(steps.map(function (st) { return st.querySelector(".dot"); }),
268           { borderColor: "#26262F", backgroundColor: "#08080A", boxShadow: "
268none" })
269      .set(steps.map(function (st) { return st.querySelector(".cap"); }), { color: "#8A8D97" });
270
271    steps.forEach(function (st, i) {
272      var son = i === SON, renk = renkAl(i), rgb = rgbAl(i);
273      tl.to(st.querySelector(".dot"), {
274        borderColor: renk,
275        backgroundColor: son ? "rgba(" + rgb + ",.25)" : "#08080A",
276        boxShadow: "0 0 10px rgba(" + rgb + (son ? ",.55)" : ",.45)"),
277        duration: .28, ease: "power2.out"
278      }, i === 0 ? 0 : ">");
279      tl.to(st.querySelector(".cap"), { color: renk, duration: .28 }, "<");
280      if (!son) tl.to(st.querySelector(".fill"), { scaleX: 1, duration: .5, ease: "none" });
281    });
282    tl.to({}, { duration: 1.5 });          /* KAYIT'ta bekle */
283
284    ScrollTrigger.create({
285      trigger: flow, start: "top 90%", end: "bottom 10%",
286      onEnter: function () { tl.play(); },
287      onEnterBack: function () { tl.play(); },
288      onLeave: function () { tl.pause(); },
289      onLeaveBack: function () { tl.pause(); }
290    });
291  } else if (flow) {
292    /* Hareket kısıtlıysa şerit tamamlanmış hâlde duruyor. Yoksa bütün
293       renk anlatımı kaybolur, beş gri nokta kalırdı. */
294    [].slice.call(flow.querySelectorAll(".step")).forEach(function (st, i, hepsi) {
295      var renk = AKIS_RENK[i % AKIS_RENK.length];
296      var rgb = AKIS_RGB[i % AKIS_RGB.length];
297      var dot = st.querySelector(".dot"), fill = st.querySelector(".fill");
298      if (dot) {
299        dot.style.borderColor = renk;
300        dot.style.boxShadow = "0 0 10px rgba(" + rgb + ",.4)";
301      }
302      st.querySelector(".cap").style.color = renk;
303      if (fill && i < hepsi.length - 1) {
304        fill.style.backgroundImage = "linear-gradient(90deg,rgba(" + rgb + ",.9),rgba(" +
305          AKIS_RGB[(i + 1) % AKIS_RGB.length] + ",.9))";
306        fill.style.transform = "scaleX(1)";
307      }
308    });
309  }
310
311  /* ── çerçeve içi hareket ─────────────────────────────────────────
312     ⚠️ Yol uzunluğu PİKSELDEN hesaplanıyor, yüzdeden değil: görüntü
313     yüzde tabanlı yükseklik almıyor (height:auto), yüzde kullanılsa
314     ekran genişliği değişince kayma miktarı yanlış oluyordu. */
315  gsap.utils.toArray(".shotview").forEach(function (view) {
316    var img = view.querySelector("img");
317    if (!img) return;
318    var tl = null;
319
320    function kur() {
321      if (tl) tl.kill();
322      var vh = view.clientHeight, ih = img.clientHeight;
323
324      if (view.dataset.anim === "scroll") {
325        var yol = ih - vh;
326        if (yol < 40) return;                 /* kayacak yer yoksa hiç başlama */
327        tl = gsap.timeline({ repeat: -1, defaults: { ease: "none" } })
328          .set(img, { y: 0 })
329          .to({}, { duration: 1.6 })          /* tepede bekle */
330          .to(img, { y: -yol, duration: yol / 26 })
331          .to({}, { duration: 1.6 })          /* dipte bekle */
332          .to(img, { y: 0, duration: yol / 60 });
333      } else {
334        var ptr = view.querySelector(".ptr"), rip = view.querySelector(".ripple");
335        if (!ptr) return;
336        var hx = (+view.dataset.x / 100) * view.clientWidth;
337        var hy = (+view.dataset.y / 100) * vh;
338        /* yalnizca Kick butonuna git ve tikla */
339        tl = gsap.timeline({ repeat: -1, repeatDelay: 1.4 })
340          .set(ptr, { x: view.clientWidth * 0.18, y: vh * 0.88, opacity: 0, scale: 1 })
341          .set(rip, { opacity: 0, scale: .3 })
342          .to(ptr, { opacity: 1, duration: .35 })
343          .to(ptr, { x: hx, y: hy, duration: 1.15, ease: "power2.inOut" })
344          .to(ptr, { scale: .82, duration: .1, yoyo: true, repeat: 1 })
345          .set(rip, { x: hx, y: hy, opacity: .9, scale: .3 }, "-=.15")
346          .to(rip, { scale: 1.6, opacity: 0, duration: .7, ease: "power2.out" })
347          .to(ptr, { opacity: 0, duration: .45 }, "-=.3");
348      }
349    }
350
351    if (img.complete) kur(); else img.addEventListener("load", kur);
352    var t; addEventListener("resize", function () { clearTimeout(t); t = setTimeout(kur, 220); });
353
354    /* üzerine gelince dursun — bakmak isteyen baksın */
355    view.addEventListener("pointerenter", function () { if (tl) tl.pause(); });
356    view.addEventListener("pointerleave", function () { if (tl) tl.resume(); });
357  });
358
359  /* ── kullanım senaryoları ────────────────────────────────────────
360     Soldaki soru seçilince sağdaki yanıt paneli değişiyor. Panelin
361     satırları da ORION_T'den geçiyor ki dil değişince çevrilsin. */
362  var QA = [
363    { t: "M4HO · susturma", r: [
364      ["ok",   "Kural",        "tekrar eden mesaj · eşik 3"],
365      ["",     "Ölçülen",      "aynı mesaj 3 kez · 8 saniye içinde"],
366      ["warn", "Karar",        "10 dk susturma"],
367      ["",     "Uygulayan",    "ORION · otomatik"],
368      ["ok",   "Kayıt",        "12:04 · gerekçesiyle yazıldı"] ] },
369    { t: "KLP-0418 · klip", r: [
370      ["",     "Kaynak",       "sohbet komutu · !klip"],
371      ["",     "İsteyen",      "tospik_fan"],
372      ["ok",   "Süre",         "0:32"],
373      ["ok",   "Konum",        "panel › Klipler"],
374      ["",     "Kayıt",        "12:04 · panele kaydedildi"] ] },
375    { t: "Heyliora · rol", r: [
376      ["",     "Sorulan",      "Kick · abonelik durumu"],
377      ["warn", "Cevap",        "abonelik sona ermiş"],
378      ["",     "Karar",        "rol geri alındı"],
379      ["ok",   "Koruma",       "cevap belirsiz olsaydı dokunulmazdı"],
380      ["ok",   "Kayıt",        "11:47 · Discord tarafına yazıldı"] ] },
381    { t: "otomod eşiği · değişiklik", r: [
382      ["",     "Ayar",         "otomod eşiği"],
383      ["",     "Önceki",       "3"],
384      ["warn", "Yeni",         "5"],
385      ["ok",   "Değiştiren",   "tospik · yayıncı"],
386      ["ok",   "Kayıt",        "11:58 · panelden"] ] },
387    { t: "uyarı kutusu · katman", r: [
388      ["",     "Katman",       "uyarı kutusu"],
389      ["warn", "Durum",        "OBS kaynağı yenilenmemiş"],
390      ["",     "ORION",        "katman yayında · veri akıyor"],
391      ["ok",   "Çözüm",        "OBS › kaynağı sağ tık › yenile"],
392      ["",     "Kayıt",        "son değişiklik 11:31"] ] }
393  ];
394
395  var ansBody = document.getElementById("ansBody"), ansTitle = document.getElementById("ansTitle");
396  if (ansBody) {
397    var qBtns = [].slice.call(document.querySelectorAll(".q"));
398    var TT = function (x) { return window.ORION_T ? window.ORION_T(x) : x; };
399    var lastQ = 0;
400    window.__orionRepaintCases = function () { paintQ(lastQ); };
401
402    function paintQ(i) {
403      var d = QA[i]; if (!d) return;
404      lastQ = i;
405      ansTitle.textContent = TT(d.t);
406      ansBody.innerHTML = d.r.map(function (x, k) {
407        return '<div class="arow ' + x[0] + '" style="animation-delay:' + (k * 45) + 'ms">' +
408          "<dt>" + TT(x[1]) + "</dt><dd>" + TT(x[2]) + "</dd></div>";
409      }).join("");
410      qBtns.forEach(function (b, j) { b.classList.toggle("on", j === i); });
411    }
412    qBtns.forEach(function (b) {
413      b.addEventListener("click", function () { paintQ(+b.dataset.q); });
414    });
415    paintQ(0);
416  }
417
418  /* ── panel sekmeleri ─────────────────────────────────────────────
419     Soldaki liste gerçek sekme; sağdaki içerik ona göre değişiyor.
420     Kullanıcı dokunmazsa kendi kendine ilerliyor, ilk tıklamada durur —
421     otomatik dönen bir şeyi okumaya çalışmak sinir bozucu olurdu. */
422  var TABS = {
423    /* ⚠️ Bu sekme ÖRNEK DEĞİL. `canli` bayrağı olan sekmede satırlar
424       buradan çizilmiyor; dört Kick odasından gelen gerçek mesajlar tek
425       akışta birleşiyor (assets/canli-sohbet.js — oda listesi orada).
426       Kanal adı bilerek hiçbir yerde yazmıyor: ziyaretçi tek bir "canlı
427       sohbet" görüyor, hangi odadan geldiğini seçmesi gerekmiyor.
428       Aşağıdaki `r` yalnızca JavaScript kapalıyken görünen yedek. */
429    sohbet: { t: "Canlı sohbet", c: "Kick · canlı akış", canli: true,
430      f: "<b>Bu sekme örnek değil.</b> Mesajlar Kick'in herkese açık sohbet akışından, doğrudan tarayıcına geliyor.",
431      r: [["g","Canlı sohbet için JavaScript gerekiyor.","—"]] },
432    simdi: { t: "Son iki dakika", c: "Öncelik · Durum · Kayıt",
433      f: "<b>Her satır kayıt altında.</b> Kimin, neden, ne zaman — sonradan sorulduğunda aranmıyor.",
434      r: [["a","<b>M4HO</b> — tekrar eden mesaj · 10 dk susturuldu","Uygulandı"],
435          ["g","Klip <b>KLP-0418</b> alındı · 0:32 · panele kaydedildi","Hazır"],
436          ["g","Yeni abone <b>Heyliora</b> · Discord rolü açıldı","Eşlendi"],
437          ["g","Yeni abone <b>Noxgun</b> · Discord rolü açıldı","Eşlendi"],
438          ["r","Bağlantı paylaşımı <b>engellendi</b> · izin listesinde değil","Bekliyor"]] },
439    mod: { t: "Moderasyon", c: "Bugün · son 24 saat", tip: "sayac",
440      f: "<b>Kurallar arka planda çalışır.</b> Sen yayına bakarken sohbet kendi kendine derleniyor.",
441      s: [["12","susturma"],["3","mesaj silme"],["1","kilit"]],
442      /* siddet: 1 hafif · 2 orta · 3 agir — soldaki cubuk buna gore doluyor */
443      r: [[3,"Tekrar eden mesaj","M4HO susturuldu","10 dk"],
444          [2,"Yasaklı kelime","Beta mesajı silindi","Anlık"],
445          [1,"Yayıncı muafiyeti","tospik kurallardan muaf","Sürekli"],
446          [1,"Yayıncı muafiyeti","Armin kurallardan muaf","Sürekli"]] },
447    klip: { t: "Klipler", c: "Son üç klip", tip: "kart",
448      f: "<b>Sohbetten komutla.</b> İzleyici <code>!klip</code> yazar, klip panele düşer.",
449      k: [["KLP-0418","0:32","sohbet komutu","hazir","Hazır"],
450          ["KLP-0417","0:48","panelden","hazir","Hazır"],
451          ["KLP-0419","1:04","sohbet komutu","suruyor","İşleniyor"]] },
452    widget: { t: "Widget ve overlay", c: "OBS katmanları", tip: "katman",
453      f: "<b>OBS'te tek bağlantı.</b> Katmanı panelden değiştir, yayında anında görünsün.",
454      w: [["Uyarı kutusu","abone · takip · bits",1],
455          ["Sohbet katmanı","son 12 mesaj",1],
456          ["Sadakat sayacı","puan tablosu",1],
457          ["Yayın hedefi","abone hedefi",0]] },
458    kayit: { t: "Kayıt defteri", c: "Kim · Ne · Ne zaman", tip: "log",
459      f: "<b>Sorulduğunda aranmıyor.</b> Her eylem, uygulayanla birlikte yazılıyor.",
460      l: [["12:04","tospik","otomod eşiğini değiştirdi"],
461          ["12:04","ORION","M4HO susturdu · tekrar eden mesaj"],
462          ["12:03","Heyliora","Discord rolü açıldı · Kick aboneliği"],
463          ["11:58","Armin","yeni komut ekledi: !discord"]] }
464  };
465
466  var rowsEl = document.getElementById("benchRows");
467  if (rowsEl) {
468    var titleEl = document.getElementById("benchTitle"),
469        chipEl  = document.getElementById("benchChip"),
470        footEl  = document.getElementById("benchFoot"),
471        tabsEl  = [].slice.call(document.querySelectorAll(".snav")),
472        auto, touched = false;
473
474    var lastKey = "simdi";
475    /* Dil degisince sekme icerigi de yeniden cizilsin diye disari aciliyor */
476    window.__orionRepaintTabs = function () { paint(lastKey); };
477
478    function T(x) { return window.ORION_T ? window.ORION_T(x) : x; }
479
480    function paint(key) {
481      var d = TABS[key]; if (!d) return;
482      lastKey = key;
483      titleEl.textContent = T(d.t);
484      chipEl.textContent = T(d.c);
485      footEl.innerHTML = T(d.f);
486
487      /* Başka sekmeye geçilince sohbet kutusu bırakılıyor. Soket AÇIK
488         kalıyor ve mesajlar tamponda birikiyor — panel 3,6 saniyede bir
489         kendi kendine döndüğü için kapatılsaydı canlı sohbet altı
490         sekmenin yalnızca birinde dinleniyor olurdu. Boşuna akmasını
491         canli-sohbet.js'teki görünürlük sayacı engelliyor. */
492      if (window.ORION_CANLI) window.ORION_CANLI.kapat();
493
494      if (d.canli && window.ORION_CANLI) {
495        rowsEl.innerHTML = "";
496        window.ORION_CANLI.ac(rowsEl);
497      } else if (d.tip === "sayac") {
498        rowsEl.innerHTML =
499          '<div class="sayaclar">' + d.s.map(function (x) {
500            return '<div><b>' + x[0] + '</b><span>' + T(x[1]) + '</span></div>';
501          }).join("") + "</div>" +
502          d.r.map(function (x, i) {
503            return '<div class="mrow" style="animation-delay:' + (i * 45) + 'ms">' +
504              '<i class="sev sev' + x[0] + '"></i>' +
505              '<span class="kural">' + T(x[1]) + '</span>' +
506              '<span class="ey">' + T(x[2]) + '</span>' +
507              '<span class="st">' + T(x[3]) + '</span></div>';
508          }).join("");
509      } else if (d.tip === "kart") {
510        rowsEl.innerHTML = '<div class="klipler">' + d.k.map(function (x, i) {
511          return '<figure class="klip" style="animation-delay:' + (i * 60) + 'ms">' +
512            '<div class="onizleme"><span class="sure">' + x[1] + "</span></div>" +
513            '<figcaption><b>' + x[0] + "</b><span>" + T(x[2]) + "</span>" +
514            '<em class="' + x[3] + '">' + T(x[4]) + "</em></figcaption></figure>";
515        }).join("") + "</div>";
516      } else if (d.tip === "katman") {
517        rowsEl.innerHTML = d.w.map(function (x, i) {
518          return '<div class="katman' + (x[2] ? " acik" : "") + '" style="animation-delay:' +
519            (i * 45) + 'ms"><span class="anahtar" aria-hidden="true"><i></i></span>' +
520            '<span class="ad"><b>' + T(x[0]) + "</b><span>" + T(x[1]) + "</span></span>" +
521            '<span class="st">' + T(x[2] ? "Yayında" : "Kapalı") + "</span></div>";
522        }).join("");
523      } else if (d.tip === "log") {
524        rowsEl.innerHTML = '<div class="logdefter">
524' + d.l.map(function (x, i) {
525          return '<div class="lsatir" style="animation-delay:' + (i * 45) + 'ms">' +
526            '<span class="zaman">' + x[0] + '</span><span class="kim">' + x[1] + "</span>" +
527            '<span class="ne">' + T(x[2]) + "</span></div>";
528        }).join("") + "</div>";
529      } else {
530        rowsEl.innerHTML = d.r.map(function (x, i) {
531          return '<div class="row" style="animation-delay:' + (i * 45) + 'ms">' +
532            '<i class="' + x[0] + '"></i><span class="txt">' + T(x[1]) + '</span>' +
533            '<span class="st">' + T(x[2]) + '</span></div>';
534        }).join("");
535      }
536      tabsEl.forEach(function (b) {
537        var on = b.dataset.tab === key;
538        b.classList.toggle("on", on);
539        b.setAttribute("aria-selected", on ? "true" : "false");
540      });
541    }
542
543    tabsEl.forEach(function (b) {
544      b.addEventListener("click", function () {
545        touched = true; clearInterval(auto); paint(b.dataset.tab);
546      });
547    });
548
549    paint("simdi");
550    if (!reduced) {
551      var keys = Object.keys(TABS), idx = 0;
552      auto = setInterval(function () {
553        if (touched) return clearInterval(auto);
554        idx = (idx + 1) % keys.length;
555        paint(keys[idx]);
556      }, 3600);
557    }
558  }
559
560  /* -- arka plan sahneleri ---------------------------------------------
561     TEK sabit canvas, TEK requestAnimationFrame dongusu. Yildizlar her
562     zaman cizilir; ustune bulundugun bolumun sahnesi biner. Sahneler
563     arasi gecis sert degil: her sahnenin kendi alfasi hedefine dogru
564     yumusakca kayiyor, boylece kaydirirken biri sonerken digeri doguyor.
565
566     !! Tek dongu olmasi onemli -- her bolume ayri canvas + ayri rAF
567     koymak bes paralel animasyon demekti, bosuna pil yakardi. */
568  var c = document.getElementById("mesh");
569  if (!c || reduced) return;
570  var g = c.getContext("2d"), W, H, dpr = Math.min(devicePixelRatio || 1, 2), tick = 0;
571
572  function rnd(a, b) { return a + Math.random() * (b - a); }
573  function line(a, b, col, al) {
574    g.strokeStyle = "rgba(" + col + "," + al + ")";
575    g.beginPath(); g.moveTo(a[0], a[1]); g.lineTo(b[0], b[1]); g.stroke();
576  }
577
578  /* -- yildizlar: her sahnede acik -- */
579  var stars = [];
580  function buildStars() {
581    stars = [];
582    var n = Math.round(Math.min(230, W * H / 7000));
583    for (var i = 0; i < n; i++) stars.push({
584      x: Math.random() * W, y: Math.random() * H,
585      r: Math.random() < .12 ? 1.6 : Math.random() * .9 + .35,
586      a: Math.random() * .55 + .15,
587      sp: Math.random() * .0018 + .0005, ph: Math.random() * 6.2832
588    });
589  }
590  function drawStars() {
591    for (var i = 0; i < stars.length; i++) {
592      var st = stars[i], tw = st.a * (0.5 + 0.5 * Math.sin(tick * st.sp + st.ph));
593      g.fillStyle = "rgba(232,236,248," + tw + ")";
594      g.beginPath(); g.arc(st.x, st.y, st.r, 0, 6.2832); g.fill();
595    }
596  }
597
598  /* -- 1) YORUNGE - hero: arkada donen tel kafes kure --
599     🔴 2026-08-28 - kullanici: "daha farklisini yap, arkada donsun" ve
600     "arka plani en uste tasi".
601
602     Eskiden burada perspektif bir SEHIR vardi (drawCity). Ufuk cizgisi
603     `H*0.58`e sabitti, yani sahne her zaman ekranin ALT yarisinda kaliyor
604     ve hero yazisinin arkasi bombos duruyordu. Ustelik kamera sadece ileri
605     kayiyordu - "donme" hissi yoktu.
606
607     Yerine kendi ekseninde donen bir tel kafes kure + iki egik yorunge
608     halkasi kondu. Merkez `H*0.40`ta: hero basliginin tam arkasi.
609
610     ⚠️ Arka yuz DAHA SOLUK ciziliyor (alfa `z` derinligine bagli). Bu
611     olmadan kure duz bir daire gibi gorunuyor, donduğu anlasilmiyor -
612     donme hissini veren tek sey bu.
613
614     ⚠️ Yazinin okunurlugu once gelir: en parlak cizgi bile 0.21 alfada.
615     `.hero::after` radyal karartmasi da ustune biniyor. */
616  var SPHERE = { lonN: 12, latN: 6, seg: 26 };
617
618  function drawOrbit(A) {
619
620    var cx = W / 2, cy = H * 0.40, R = Math.min(W, H) * 0.36;
621    var rot = tick * 0.00016;                 // yavas: hipnotik degil, sakin
622    var tc = Math.cos(0.38), ts = Math.sin(0.38);   // sabit eksen egimi
623    var C = "152,160,182";
624
625    /* Kure yuzeyindeki bir nokta -> ekran. Donus Y ekseni etrafinda,
626       sonra sabit egim. Donen `z` derinligi alfa icin geri veriliyor. */
627    function pt(lat, lon) {
628      var cl = Math.cos(lat),
629          x = cl * Math.sin(lon + rot),
630          y = Math.sin(lat),
631          z = cl * Math.cos(lon + rot);
632      return [cx + x * R, cy + (y * tc - z * ts) * R, y * ts + z * tc];
633    }
634
635    /* Derinlige gore alfa: on yuz belirgin, arka yuz silik. */
636    function al(z, base) { return base * (0.28 + 0.72 * (z * 0.5 + 0.5)) * A; }
637
638    var i, j, a, b, HALF = Math.PI / 2;
639
640    // meridyenler (boylam)
641    for (i = 0; i < SPHERE.lonN; i++) {
642      var lon = (i / SPHERE.lonN) * Math.PI;      // yarim tur yeter: kure simetrik
643      a = pt(-HALF, lon);
644      for (j = 1; j <= SPHERE.seg; j++) {
645        b = pt(-HALF + (j / SPHERE.seg) * Math.PI, lon);
646        line(a, b, C, al((a[2] + b[2]) / 2, 0.21));
647        a = b;
648      }
649    }
650
651    // paraleller (enlem)
652    for (i = 1; i <= SPHERE.latN; i++) {
653      var lat = -HALF + (i / (SPHERE.latN + 1)) * Math.PI;
654      a = pt(lat, 0);
655      for (j = 1; j <= SPHERE.seg * 2; j++) {
656        b = pt(lat, (j / (SPHERE.seg * 2)) * 6.2832);
657        line(a, b, C, al((a[2] + b[2]) / 2, 0.17));
658        a = b;
659      }
660    }
661
662    /* Iki egik yorunge halkasi + uzerinde kosan birer isik.
663       Kureden bagimsiz donuyorlar; sahneye derinlik veren sey bu. */
664    var orbits = [{ tilt: 0.95, r: 1.30, sp: 0.00021, ph: 0 },
665                  { tilt: -0.62, r: 1.62, sp: -0.00013, ph: 2.1 }];
666
667    for (i = 0; i < orbits.length; i++) {
668      var o = orbits[i], ot = Math.cos(o.tilt), os = Math.sin(o.tilt),
669          rr = R * o.r, spin = tick * o.sp + o.ph;
670
671      function opt(t) {
672        var x = Math.cos(t + spin), z = Math.sin(t + spin);
673        var y2 = -z * os, z2 = z * ot;
674        return [cx + x * rr, cy + (y2 * tc - z2 * ts) * rr, y2 * ts + z2 * tc];
675      }
676
677      a = opt(0);
678      for (j = 1; j <= 72; j++) {
679        b = opt((j / 72) * 6.2832);
680        line(a, b, C, al((a[2] + b[2]) / 2, 0.16));
681        a = b;
682      }
683
684      var d = opt(spin * 3.1);
685      g.fillStyle = "rgba(95,212,155," + (0.5 * A) + ")";
686      g.beginPath(); g.arc(d[0], d[1], 1.9, 0, 6.2832); g.fill();
687    }
688  }
689
690  /* -- 2) AG - sorun: birbirine baglanan noktalar --
691     "Her sey ayri bir yerde" bolumunun altinda duruyor; kopuk noktalarin
692     ancak yaklasinca birlesmesi o bolumun anlattigi seyin gorsel karsiligi. */
693  var web = [];
694  function buildWeb() {
695    web = [];
696    var n = Math.round(Math.min(95, W / 15));
697    for (var i = 0; i < n; i++) web.push({
698      x: Math.random() * W, y: Math.random() * H,
699      vx: rnd(-.16, .16), vy: rnd(-.16, .16) });
700  }
701  function drawWeb(A) {
702    g.lineWidth = 1;
703    var R = 185;
704    for (var i = 0; i < web.length; i++) {
705      var a = web[i];
706      a.x += a.vx; a.y += a.vy;
707      if (a.x < -40) a.x = W + 40;
708      if (a.x > W + 40) a.x = -40;
709      if (a.y < -40) a.y = H + 40;
710      if (a.y > H + 40) a.y = -40;
711      for (var j = i + 1; j < web.length; j++) {
712        var b = web[j], dx = a.x - b.x, dy = a.y - b.y, d = Math.sqrt(dx * dx + dy * dy);
713        if (d < R) line([a.x, a.y], [b.x, b.y], "150,160,190", (1 - d / R) * 0.26 * A);
714      }
715      g.fillStyle = "rgba(190,198,220," + (0.5 * A) + ")";
716      g.beginPath(); g.arc(a.x, a.y, 1.5, 0, 6.2832); g.fill();
717    }
718  }
719
720  /* -- 3) AKIS - panel: soldan saga akan veri cizgileri -- */
721  var flows = [];
722  function buildFlow() {
723    flows = [];
724    for (var i = 0; i < 26; i++) flows.push({
725      y: Math.random() * H, x: Math.random() * W,
726      len: rnd(60, 320), v: rnd(.5, 2.6), a: rnd(.05, .2), warm: Math.random() < .25 });
727  }
728  function drawFlow(A) {
729    g.lineWidth = 1;
730    for (var i = 0; i < flows.length; i++) {
731      var f = flows[i], col = f.warm ? "95,212,155" : "160,170,195";
732      var grd = g.createLinearGradient(f.x, f.y, f.x + f.len, f.y);
733      grd.addColorStop(0, "rgba(" + col + ",0)");
734      grd.addColorStop(.6, "rgba(" + col + "," + (f.a * 1.8 * A) + ")");
735      grd.addColorStop(1, "rgba(" + col + ",0)");
736      g.strokeStyle = grd;
737      g.beginPath(); g.moveTo(f.x, f.y); g.lineTo(f.x + f.len, f.y); g.stroke();
738      f.x += f.v;
739      if (f.x > W + 40) { f.x = -f.len - 40; f.y = Math.random() * H; }
740    }
741  }
742
743  /* -- 4) HUZME - urunler: yavas capraz isik -- */
744  function drawRays(A) {
745    for (var i = 0; i < 7; i++) {
746      var ph = tick * 0.00006 + i * 0.9;
747      var x = ((Math.sin(ph) * 0.5 + 0.5) * (W + 700)) - 350;
748      var grd = g.createLinearGradient(x, -100, x + 260, H + 100);
749      grd.addColorStop(0, "rgba(150,160,195,0)");
750      grd.addColorStop(.5, "rgba(150,160,195," + (0.055 * A) + ")");
751      grd.addColorStop(1, "rgba(150,160,195,0)");
752      g.fillStyle = grd;
753      g.beginPath();
754      g.moveTo(x, -100); g.lineTo(x + 150, -100);
755      g.lineTo(x + 410, H + 100); g.lineTo(x + 260, H + 100);
756      g.closePath(); g.fill();
757    }
758  }
759
760  /* -- 5) IZGARA - araclar: nabiz atan perspektif zemin -- */
761  function drawGrid(A) {
762    g.lineWidth = 1;
763    var hz = H * 0.42, C = "150,158,182";
764    for (var r = 1; r <= 20; r++) {
765      var t = r / 20, y = hz + Math.pow(t, 2.0) * (H - hz) * 1.15;
766      var pulse = 0.5 + 0.5 * Math.sin(tick * 0.0011 - r * 0.35);
767      line([0, y], [W, y], C, (0.05 + 0.09 * pulse) * (1 - t * .5) * A);
768    }
769    for (var i = -14; i <= 14; i++) {
770      line([W / 2 + i * 26, hz], [W / 2 + i * 300, H], C, 0.06 * A);
771    }
772  }
773
774  /* -- 6) NABIZ - islevler: merkezden yayilan halkalar --
775     Radar atisi: her halka dogar, buyur, soner. Ic halkalar keskin,
776     disa dogru hem soluyor hem inceliyor - "yayilma" hissi bundan. */
777  function drawPulse(A) {
778    var cx = W / 2, cy = H * 0.46, max = Math.max(W, H) * 0.66, N = 7, i;
779    for (i = 0; i < N; i++) {
780      var t = ((tick * 0.00011) + i / N) % 1;
781      var r = t * max, a = Math.pow(1 - t, 1.6) * 0.30 * A;
782      if (a < 0.004) continue;
783      g.lineWidth = 1 + (1 - t) * 1.1;
784      g.strokeStyle = "rgba(150,158,182," + a + ")";
785      g.beginPath(); g.ellipse(cx, cy, r, r * 0.82, 0, 0, 6.2832); g.stroke();
786    }
787    g.lineWidth = 1;
788    var cg = g.createRadialGradient(cx, cy, 0, cx, cy, 90);
789    cg.addColorStop(0, "rgba(95,212,155," + (0.13 * A) + ")");
790    cg.addColorStop(1, "rgba(95,212,155,0)");
791    g.fillStyle = cg;
792    g.beginPath(); g.arc(cx, cy, 90, 0, 6.2832); g.fill();
793  }
794
795  /* -- 7) DALGA - akis: ust uste kayan sinus seritleri --
796     Iki farkli frekans ust uste bindirildi; tek sinus fazla duzenli
797     duruyor, ikisi birlesince akarsu gibi dalgalaniyor. */
798  function drawWave(A) {
799    for (var b = 0; b < 6; b++) {
800      var yb = H * (0.24 + b * 0.105), amp = 34 + b * 11,
801          sp = tick * (0.00040 + b * 0.00009), k = 0.0048 + b * 0.0008,
802          vurgu = (b === 2);                       // tek serit ORION yesili
803      g.lineWidth = vurgu ? 1.4 : 1;
804      g.strokeStyle = vurgu
805        ? "rgba(95,212,155," + (0.16 * A) + ")"
806        : "rgba(152,162,192," + ((0.20 - b * 0.021) * A) + ")";
807      g.beginPath();
808      for (var x = 0; x <= W; x += 12) {
809        var y = yb + Math.sin(x * k + sp) * amp
810                   + Math.sin(x * k * 0.37 - sp * 1.7) * amp * 0.45;
811        if (x === 0) g.moveTo(x, y); else g.lineTo(x, y);
812      }
813      g.stroke();
814    }
815    g.lineWidth = 1;
816  }
817
818  /* -- 8) YAGMUR - nefes: dusen veri cizgileri -- */
819  var drops = [];
820  function buildDrops() {
821    drops = [];
822    var n = Math.round(Math.min(70, W / 22));
823    for (var i = 0; i < n; i++) drops.push({
824      x: Math.random() * W, y: Math.random() * H,
825      len: rnd(30, 110), v: rnd(.55, 1.7), a: rnd(.09, .26)
826    });
827  }
828  function drawRain(A) {
829    g.lineWidth = 1;
830    for (var i = 0; i < drops.length; i++) {
831      var d = drops[i];
832      var grd = g.createLinearGradient(d.x, d.y, d.x, d.y + d.len);
833      grd.addColorStop(0, "rgba(150,160,190,0)");
834      grd.addColorStop(1, "rgba(150,160,190," + (d.a * 1.5 * A) + ")");
835      g.strokeStyle = grd;
836      g.beginPath(); g.moveTo(d.x, d.y); g.lineTo(d.x, d.y + d.len); g.stroke();
837      d.y += d.v;
838      if (d.y > H) { d.y = -d.len; d.x = Math.random() * W; }
839    }
840  }
841
842  /* -- 9) SARMAL - senaryolar: donen gokada --
843     ⚠️ Ilk surumde 3x42 noktaydi ve ekranda "karalama" gibi duruyordu.
844     Kol basina nokta sayisi artirildi, yaricap buyutuldu, nokta boyu ve
845     alfasi merkezden disa dogru azaliyor - gokada his ancak boyle olusuyor. */
846  function drawSpiral(A) {
847    var cx = W / 2, cy = H * 0.47, R = Math.min(W, H) * 0.66, rot = tick * 0.000075;
848    for (var arm = 0; arm < 3; arm++) {
849      var base = rot + arm * 2.094;
850      for (var i = 3; i < 96; i++) {
851        var t = i / 96, ang = base + Math.pow(t, 0.85) * 5.4, r = t * R;
852        var a = Math.pow(1 - t, 1.35) * 0.62 * A;
853        if (a < 0.004) continue;
854        // Her yedinci nokta yesil: gokadaya renk atiyor, tek duze olmuyor.
855        g.fillStyle = (i % 7 === 0)
856          ? "rgba(95,212,155," + (a * 0.8) + ")"
857          : "rgba(158,167,194," + a + ")";
858        g.beginPath();
859        g.arc(cx + Math.cos(ang) * r, cy + Math.sin(ang) * r * 0.42,
860              0.8 + (1 - t) * 1.9, 0, 6.2832);
861        g.fill();
862      }
863    }
864  }
865
866  /* -- 10) PETEK - eklentiler: kayan altigen kafes --
867     ⚠️ Ilk surumde kafes ekranin TAMAMINI esit parlaklikta kapliyordu ve
868     duvar kagidi gibi duruyordu. Artik merkezden disa dogru soluyor ve
869     icinde birkac hucre sirayla parliyor - desen degil, canli bir doku. */
870  function drawHex(A) {
871    var R = 52, w = R * 1.732, h = R * 1.5,
872        off = (tick * 0.010) % w, cx = W / 2, cy = H * 0.47,
873        maxD = Math.max(W, H) * 0.62;
874
875    for (var row = -1; row * h < H + R; row++) {
876      for (var col = -1; col * w < W + w; col++) {
877        var x0 = col * w + (row % 2 ? w / 2 : 0) - off, y0 = row * h;
878        var d = Math.sqrt((x0 - cx) * (x0 - cx) + (y0 - cy) * (y0 - cy) * 1.6);
879        var f = 1 - Math.min(1, d / maxD);
880        if (f <= 0.02) continue;
881
882        // sirayla parlayan hucreler
883        var puls = 0.5 + 0.5 * Math.sin(tick * 0.0016 + (row * 3 + col) * 1.1);
884        var a = (0.05 + 0.13 * f) * (0.65 + 0.35 * puls) * A;
885
886        g.strokeStyle = "rgba(150,158,182," + a + ")";
887        g.beginPath();
888        for (var k = 0; k < 6; k++) {
889          var ang = (Math.PI / 3) * k - Math.PI / 6;
890          var x = x0 + Math.cos(ang) * R, y = y0 + Math.sin(ang) * R;
891          if (k === 0) g.moveTo(x, y); else g.lineTo(x, y);
892        }
893        g.closePath(); g.stroke();
894      }
895    }
896  }
897
898  /* -- 11) TARAMA - guven: izgara uzerinde gecen tarama cizgisi --
899     ⚠️ Ilk surumde tarama 240px'lik kalin yesil bir bulut olarak geciyordu;
900     ekranda bulasik bir leke gibi duruyordu. Artik INCE ve KESKIN bir cizgi
901     + arkasinda kisa bir kuyruk: tarayici his buradan geliyor. */
902  function drawScan(A) {
903    var C = "150,158,182", i;
904    for (i = 1; i < 10; i++) line([0, H * i / 10], [W, H * i / 10], C, 0.05 * A);
905    for (i = 1; i < 15; i++) line([W * i / 15, 0], [W * i / 15, H], C, 0.042 * A);
906
907    var y = ((tick * 0.052) % (H + 200)) - 100;
908
909    // kuyruk: cizginin YUKARISINDA kalir, gectigi yeri belli eder
910    var grd = g.createLinearGradient(0, y - 130, 0, y);
911    grd.addColorStop(0, "rgba(95,212,155,0)");
912    grd.addColorStop(1, "rgba(95,212,155," + (0.09 * A) + ")");
913    g.fillStyle = grd;
914    g.fillRect(0, y - 130, W, 130);
915
916    // cizginin kendisi
917    g.strokeStyle = "rgba(95,212,155," + (0.34 * A) + ")";
918    g.lineWidth = 1.2;
919    g.beginPath(); g.moveTo(0, y); g.lineTo(W, y); g.stroke();
920    g.lineWidth = 1;
921  }
922
923  /* -- sahne yonetimi --
924     🔴 2026-08-28 - kullanici: "farkli farkli olsun her sayfada, sekmede".
925
926     ONCEDEN iki sorun vardi:
927       1. Bes sahne on bir bolume dagitilmisti, yani ayni arka plan sayfa
928          boyunca uc kez tekrar ediyordu.
929       2. ANA SAYFA DISINDAKI ONBIR SAYFADA hicbir bolum kimligi eslesmiyor,
930          `best` 0'da kaliyor ve HEPSINDE ayni sahne (hero'nunki) donuyordu.
931
932     Artik her bolumun ve her sayfanin kendine ait bir sahnesi var. Yeni bir
933     bolum ya da sayfa eklenirse buraya da bir satir eklenmeli - eslesme
934     bulunamazsa yine ilk sahneye dusulur. */
935  var SCENES = [
936    { id: "hero",       draw: drawOrbit,  a: 0, t: 0 },   // kure
937    { id: "urunler",    draw: drawRays,   a: 0, t: 0 },   // huzme
938    { id: "eklentiler", draw: drawHex,    a: 0, t: 0 },   // petek
939    { id: "sorun",      draw: drawWeb,    a: 0, t: 0 },   // ag
940    { id: "panel",      draw: drawFlow,   a: 0, t: 0 },   // akis
941    { id: "islevler",   draw: drawPulse,  a: 0, t: 0 },   // nabiz
942    { id: "akis",       draw: drawWave,   a: 0, t: 0 },   // dalga
943    { id: "guven",      draw: drawScan,   a: 0, t: 0 },   // tarama
944    { id: "senaryolar", draw: drawSpiral, a: 0, t: 0 },   // sarmal
945    { id: "nefes",      draw: drawRain,   a: 0, t: 0 },   // yagmur
946    { id: "araclar",    draw: drawGrid,   a: 0, t: 0 }    // izgara
947  ];
948
949  function sceneIndex(id) {
950    for (var i = 0; i < SCENES.length; i++) if (SCENES[i].id === id) return i;
951    return 0;
952  }
953
954  /* Bolumu olmayan sayfalarin kendi sahnesi. Anahtar adres yolundan
955     cozuluyor; listede yoksa kure ile aciliyor. */
956  var SAYFA_SAHNE = {
957    "/orionmod":          "panel",        // akis
958    "/orionmodes":        "araclar",      // izgara
959    "/orionmod-eklenti":  "islevler",     // nabiz
960    "/clip-helper":       "guven",        // tarama
961    "/kick-clipper":      "akis",         // dalga
962    "/kick-chat-overlay": "eklentiler",   // petek
963    "/musivora":          "senaryolar",   // sarmal
964    "/link-hunter":       "nefes",        // yagmur
965    "/gizlilik":          "sorun",        // ag
966    "/kullanim-sartlari": "urunler",      // huzme
967    "/404":               "hero"          // kure
968  };
969
970  function sayfaVarsayilani() {
971    var yol = location.pathname.replace(/\.html$/, "").replace(/\/+$/, "");
972    if (!yol) return sceneIndex("hero");                       // ana sayfa
973    return SAYFA_SAHNE[yol] ? sceneIndex(SAYFA_SAHNE[yol]) : sceneIndex("hero");
974  }
975
976  var VARSAYILAN = sayfaVarsayilani();
977  SCENES[VARSAYILAN].a = 1;
978  SCENES[VARSAYILAN].t = 1;
979
980  function pickScene() {
981    var mid = innerHeight * 0.45, best = -1;
982    for (var i = 0; i < SCENES.length; i++) {
983      var el = SCENES[i].id === "hero"
984        ? document.querySelector(".hero")
985        : document.getElementById(SCENES[i].id);
986      if (!el) continue;
987      var r = el.getBoundingClientRect();
988      if (r.top <= mid && r.bottom >
988= mid) best = i;
989    }
990    // Hicbir bolum orta noktada degil (ya da sayfada hic bolum yok):
991    // o sayfanin kendi sahnesi kalir - eskiden hep hero'nunki kaliyordu.
992    if (best < 0) best = VARSAYILAN;
993    for (var j = 0; j < SCENES.length; j++) SCENES[j].t = (j === best) ? 1 : 0;
994  }
995
996  addEventListener("scroll", pickScene, { passive: true });
997
998  function rs() {
999    W = c.offsetWidth; H = c.offsetHeight;
1000    c.width = W * dpr; c.height = H * dpr;
1001    g.setTransform(dpr, 0, 0, dpr, 0, 0);
1002    buildStars(); buildWeb(); buildFlow(); buildDrops();
1003  }
1004
1005  function frame() {
1006    g.clearRect(0, 0, W, H);
1007    drawStars();
1008    for (var i = 0; i < SCENES.length; i++) {
1009      var sc = SCENES[i];
1010      sc.a += (sc.t - sc.a) * 0.045;
1011      if (sc.a > 0.01) sc.draw(sc.a);
1012    }
1013    tick += 16;
1014    requestAnimationFrame(frame);
1015  }
1016
1017  rs(); pickScene(); frame();
1018  var to;
1019  addEventListener("resize", function () { clearTimeout(to); to = setTimeout(rs, 160); });
1020})();

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.