Compare commits
11
Commits
765d84f00a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff59171296 | ||
|
|
2e8eef14ee | ||
|
|
9384a96e7e | ||
|
|
41c33d65ce | ||
|
|
7c62b88d0e | ||
|
|
39660d07b7 | ||
|
|
ab0670f227 | ||
|
|
8bf89df5c9 | ||
|
|
577f8bd61a | ||
|
|
122790ac91 | ||
|
|
926682117b |
+511
-120
@@ -3,72 +3,143 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Toplantı 3D — Orijinal / Türkçe</title>
|
||||
<title>Toplantı Odası — İnteraktif 3D Kayıt</title>
|
||||
<style>
|
||||
:root{ --bg:#0d1117; --panel:#161b22cc; --border:#30363d; --txt:#e6edf3; --mut:#8b949e; --accent:#2f81f7; }
|
||||
:root{ --bg:#0a0e14; --panel:#12161fdd; --border:#2b3240; --txt:#e8edf4; --mut:#8b95a6;
|
||||
--accent:#2f81f7; --gold:#e0b400; --glow:0 0 18px rgba(47,129,247,.35); }
|
||||
*{box-sizing:border-box}
|
||||
html,body{margin:0;height:100%;background:var(--bg);color:var(--txt);font-family:"Segoe UI",system-ui,sans-serif;overflow:hidden}
|
||||
html,body{margin:0;height:100%;background:var(--bg);color:var(--txt);
|
||||
font-family:"Segoe UI",system-ui,sans-serif;overflow:hidden;user-select:none}
|
||||
#scene{position:fixed;inset:0}
|
||||
#topbar{position:fixed;top:0;left:0;right:0;height:52px;display:flex;align-items:center;gap:14px;
|
||||
padding:0 16px;background:linear-gradient(#0d1117ee,#0d111700);z-index:10;pointer-events:none}
|
||||
#topbar h1{font-size:15px;margin:0;font-weight:600;pointer-events:auto}
|
||||
#topbar .sub{font-size:12px;color:var(--mut);font-weight:400}
|
||||
|
||||
/* ---- ÜST BAR ---- */
|
||||
#topbar{position:fixed;top:0;left:0;right:0;height:54px;display:flex;align-items:center;gap:12px;
|
||||
padding:0 16px;background:linear-gradient(#0a0e14f0,#0a0e1400);z-index:10;pointer-events:none}
|
||||
#topbar h1{font-size:15px;margin:0;font-weight:700;letter-spacing:.4px;pointer-events:auto;
|
||||
text-shadow:0 0 14px rgba(47,129,247,.5)}
|
||||
#topbar .sub{font-size:11px;color:var(--mut);font-weight:400;letter-spacing:0}
|
||||
.spacer{flex:1}
|
||||
.toggle{pointer-events:auto;display:flex;background:#21262d;border:1px solid var(--border);border-radius:20px;overflow:hidden}
|
||||
.toggle button{background:none;border:0;color:var(--mut);padding:7px 15px;font-size:13px;cursor:pointer;font-weight:600}
|
||||
.toggle{pointer-events:auto;display:flex;background:#161b26;border:1px solid var(--border);
|
||||
border-radius:20px;overflow:hidden;box-shadow:var(--glow)}
|
||||
.toggle button{background:none;border:0;color:var(--mut);padding:7px 15px;font-size:13px;cursor:pointer;font-weight:700}
|
||||
.toggle button.on{background:var(--accent);color:#fff}
|
||||
.toggle button.on.trm{background:#8957e5}
|
||||
#legend{position:fixed;top:60px;left:12px;z-index:10;background:var(--panel);border:1px solid var(--border);
|
||||
border-radius:10px;padding:10px 12px;font-size:11.5px;backdrop-filter:blur(6px);max-width:220px}
|
||||
#legend .row{display:flex;align-items:center;gap:7px;margin-top:5px}
|
||||
#legend .dot{width:11px;height:11px;border-radius:50%;flex:none}
|
||||
#subtitle{position:fixed;left:50%;transform:translateX(-50%);bottom:90px;width:min(760px,94vw);z-index:10;
|
||||
background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:6px 14px;backdrop-filter:blur(8px);
|
||||
text-align:center;transition:opacity .2s}
|
||||
#subtitle .who{font-weight:700;font-size:12px;margin-bottom:1px}
|
||||
#subtitle .orig{font-size:12.5px;line-height:1.24}
|
||||
#subtitle .tr{font-size:12.5px;line-height:1.24;color:var(--mut);margin-top:1px}
|
||||
#subtitle.trmode .orig{color:var(--mut);font-size:12.5px}
|
||||
#subtitle.trmode .tr{color:var(--txt)}
|
||||
.badge{display:inline-block;font-size:10px;background:#3d2a00;color:#e0b400;border:1px solid #6b4a00;
|
||||
border-radius:6px;padding:1px 6px;margin-left:6px;vertical-align:middle}
|
||||
#controls{position:fixed;left:0;right:0;bottom:0;z-index:10;background:linear-gradient(#0d111700,#0d1117ee 42%);padding:12px 18px 14px}
|
||||
.iconbtn{pointer-events:auto;background:#161b26;border:1px solid var(--border);color:var(--mut);
|
||||
border-radius:20px;padding:7px 13px;font-size:12.5px;cursor:pointer;font-weight:700}
|
||||
.iconbtn.on{color:#fff;border-color:var(--accent);box-shadow:var(--glow)}
|
||||
|
||||
/* ---- SOL PANEL: taraflar ---- */
|
||||
#legend{position:fixed;top:62px;left:12px;z-index:10;background:var(--panel);border:1px solid var(--border);
|
||||
border-radius:12px;padding:10px 12px;font-size:11.5px;backdrop-filter:blur(8px);max-width:228px}
|
||||
#legend>b{font-size:12px;letter-spacing:.4px}
|
||||
#legend .row{display:flex;align-items:center;gap:7px;margin-top:5px;cursor:pointer}
|
||||
#legend .row:hover{color:#fff}
|
||||
#legend .dot{width:11px;height:11px;border-radius:50%;flex:none;box-shadow:0 0 6px currentColor}
|
||||
|
||||
/* ---- SAĞ PANEL: skor ---- */
|
||||
#stats{position:fixed;top:62px;right:12px;z-index:10;background:var(--panel);border:1px solid var(--border);
|
||||
border-radius:12px;padding:10px 12px;font-size:11px;backdrop-filter:blur(8px);width:216px}
|
||||
#stats>b{font-size:12px;letter-spacing:.4px}
|
||||
.srow{margin-top:6px;transition:transform .15s}
|
||||
.srow.on{transform:translateX(-3px)}
|
||||
.srow .nm{display:flex;justify-content:space-between;font-size:11px;margin-bottom:2px}
|
||||
.srow.on .nm{color:#fff;font-weight:700;text-shadow:0 0 8px rgba(255,255,255,.4)}
|
||||
.srow .bar{height:5px;border-radius:3px;background:#1c2230;overflow:hidden}
|
||||
.srow .fill{height:100%;border-radius:3px;opacity:.85}
|
||||
.srow.on .fill{opacity:1;box-shadow:0 0 8px currentColor}
|
||||
|
||||
/* ---- RPG DİYALOG KUTUSU ---- */
|
||||
#dlg{position:fixed;left:50%;transform:translateX(-50%);bottom:92px;width:min(820px,94vw);z-index:10;
|
||||
background:linear-gradient(#141a26ee,#0e131de8);border:1px solid #34405a;border-radius:14px;
|
||||
padding:10px 14px 11px;backdrop-filter:blur(10px);display:flex;gap:12px;align-items:flex-start;
|
||||
box-shadow:0 10px 40px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.05);transition:opacity .2s}
|
||||
#dlgAva{width:46px;height:46px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;
|
||||
font-weight:800;font-size:19px;color:#0a0e14;margin-top:3px;box-shadow:0 0 14px currentColor}
|
||||
#dlgBody{flex:1;min-width:0;text-align:left}
|
||||
#dlgName{font-weight:800;font-size:13px;letter-spacing:.4px;margin-bottom:3px}
|
||||
#dlgName .arrow{color:var(--mut);font-weight:400;margin:0 5px}
|
||||
#dlgName .target{color:#cdd6e4}
|
||||
#dlgMain{font-size:13.5px;line-height:1.38;min-height:19px}
|
||||
#dlgMain .cursor{display:inline-block;width:7px;background:#e8edf4;height:13px;margin-left:2px;
|
||||
animation:blink .8s steps(1) infinite;vertical-align:middle}
|
||||
@keyframes blink{50%{opacity:0}}
|
||||
#dlgSub{font-size:11.5px;line-height:1.3;color:var(--mut);margin-top:3px}
|
||||
|
||||
/* ---- ALT KONTROLLER ---- */
|
||||
#controls{position:fixed;left:0;right:0;bottom:0;z-index:10;
|
||||
background:linear-gradient(#0a0e1400,#0a0e14f5 45%);padding:12px 18px 13px}
|
||||
#tl{width:100%;height:34px;display:block;cursor:pointer;border-radius:6px}
|
||||
#bar{display:flex;align-items:center;gap:12px;margin-top:8px}
|
||||
.btn{background:#21262d;border:1px solid var(--border);color:var(--txt);width:40px;height:40px;border-radius:50%;
|
||||
font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center}
|
||||
.btn:hover{border-color:var(--accent)}
|
||||
.btn.play{width:46px;height:46px;font-size:17px;background:var(--accent);border-color:var(--accent)}
|
||||
.btn{background:#161b26;border:1px solid var(--border);color:var(--txt);width:40px;height:40px;border-radius:50%;
|
||||
font-size:15px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.15s}
|
||||
.btn:hover{border-color:var(--accent);box-shadow:var(--glow)}
|
||||
.btn.play{width:48px;height:48px;font-size:17px;background:linear-gradient(135deg,#2f81f7,#1a5fd0);
|
||||
border-color:#2f81f7;box-shadow:0 0 20px rgba(47,129,247,.45)}
|
||||
#time{font-variant-numeric:tabular-nums;font-size:13px;color:var(--mut);min-width:120px}
|
||||
#hint{font-size:11px;color:var(--mut)}
|
||||
@media(max-width:640px){
|
||||
#subtitle{bottom:138px}
|
||||
|
||||
/* ---- GİRİŞ EKRANI ---- */
|
||||
#intro{position:fixed;inset:0;z-index:50;background:radial-gradient(ellipse at 50% 38%,#131a28 0%,#0a0e14 70%);
|
||||
display:flex;align-items:center;justify-content:center;text-align:center}
|
||||
#intro .in{max-width:520px;padding:24px}
|
||||
#intro h2{font-size:30px;margin:0 0 4px;letter-spacing:1.5px;font-weight:800;
|
||||
background:linear-gradient(180deg,#fff,#7fb0f5);-webkit-background-clip:text;background-clip:text;color:transparent;
|
||||
text-shadow:0 0 30px rgba(47,129,247,.35)}
|
||||
#intro .sm{color:var(--mut);font-size:13px;margin-bottom:22px}
|
||||
#intro .feats{display:flex;gap:14px;justify-content:center;flex-wrap:wrap;margin-bottom:26px;font-size:11.5px;color:#aab6c8}
|
||||
#intro .feats span{background:#141a26;border:1px solid var(--border);border-radius:8px;padding:6px 10px}
|
||||
#startBtn{background:linear-gradient(135deg,#2f81f7,#1a5fd0);color:#fff;border:0;border-radius:30px;
|
||||
padding:14px 46px;font-size:17px;font-weight:800;letter-spacing:1px;cursor:pointer;
|
||||
box-shadow:0 0 34px rgba(47,129,247,.55);animation:pulse 1.8s ease-in-out infinite}
|
||||
@keyframes pulse{50%{box-shadow:0 0 50px rgba(47,129,247,.85);transform:scale(1.03)}}
|
||||
#intro .keys{margin-top:22px;font-size:11px;color:#66707f}
|
||||
|
||||
.badge{display:inline-block;font-size:10px;background:#3d2a00;color:var(--gold);border:1px solid #6b4a00;
|
||||
border-radius:6px;padding:1px 6px;margin-left:6px;vertical-align:middle}
|
||||
|
||||
@media(max-width:760px){
|
||||
#stats{display:none}
|
||||
#legend{max-width:150px;font-size:10px;padding:7px 9px;top:58px}
|
||||
#legend .desc{display:none}
|
||||
#dlg{bottom:132px;padding:8px 10px}
|
||||
#dlgAva{width:36px;height:36px;font-size:15px}
|
||||
#dlgMain{font-size:12px}
|
||||
#dlgSub{font-size:10.5px}
|
||||
#hint{display:none}
|
||||
#bar{flex-wrap:wrap}
|
||||
#topbar h1{font-size:13px}
|
||||
#topbar h1{font-size:12.5px}
|
||||
#topbar .sub{display:none}
|
||||
.toggle button{padding:6px 10px;font-size:12px}
|
||||
#legend{max-width:150px;font-size:10px;padding:7px 9px;top:56px}
|
||||
#legend b{font-size:10.5px}
|
||||
.iconbtn{padding:6px 9px;font-size:11px}
|
||||
#intro h2{font-size:22px}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="scene"></div>
|
||||
|
||||
<div id="topbar">
|
||||
<h1>Toplantı — 3D Oda <span class="sub">· uzlaşma görüşmesi (düzenlenmiş kayıt)</span></h1>
|
||||
<h1>⚖️ TOPLANTI ODASI <span class="sub">· interaktif 3D kayıt · kim ne dedi, kime dedi</span></h1>
|
||||
<div class="spacer"></div>
|
||||
<button class="iconbtn on" id="camBtn" title="Oto kamera: konuşana odaklan">🎥 Oto</button>
|
||||
<div class="toggle" id="langToggle">
|
||||
<button data-m="orig" class="on">🔊 Orijinal</button>
|
||||
<button data-m="tr">🇹🇷 Türkçe</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="legend"><b>Masadaki kişiler</b><div id="legendRows"></div></div>
|
||||
<div id="subtitle">
|
||||
<div class="who" id="subWho">—</div>
|
||||
<div class="orig" id="subOrig">Başlamak için ▶ tuşuna bas</div>
|
||||
<div class="tr" id="subTr"></div>
|
||||
|
||||
<div id="legend"><b>KİŞİLER & TARAFLAR</b><div id="legendRows"></div></div>
|
||||
<div id="stats"><b>📊 KONUŞMA İSTATİSTİĞİ</b><div id="statRows"></div></div>
|
||||
|
||||
<div id="dlg">
|
||||
<div id="dlgAva">?</div>
|
||||
<div id="dlgBody">
|
||||
<div id="dlgName">—</div>
|
||||
<div id="dlgMain">Başlamak için ▶</div>
|
||||
<div id="dlgSub"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="controls">
|
||||
<canvas id="tl"></canvas>
|
||||
<div id="bar">
|
||||
@@ -77,15 +148,29 @@
|
||||
<button class="btn" id="next" title="Sonraki konuşma">⏭</button>
|
||||
<span id="time">00:00 / 00:00</span>
|
||||
<div class="spacer"></div>
|
||||
<span id="hint">Zaman çizelgesine tıkla/sürükle · fareyle sahneyi döndür · çift tık kişi→ilk sözü</span>
|
||||
<span id="hint">🖱️ sürükle: kamera · kişiye tıkla: sıradaki sözü · 📄 faturalar · boşluk: oynat/durdur · ←→: 5sn</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loadErr" style="display:none;position:fixed;inset:0;z-index:999;background:#0d1117;color:#e6edf3;
|
||||
|
||||
<div id="intro">
|
||||
<div class="in">
|
||||
<h2>TOPLANTI ODASI</h2>
|
||||
<div class="sm">İnteraktif 3D uzlaşma kaydı — dolandırıcılık görüşmesi · 22 dk</div>
|
||||
<div class="feats">
|
||||
<span>🎧 Orijinal + Türkçe dublaj</span><span>💡 Konuşan kişi ışıkla</span>
|
||||
<span>🎯 Kime söylediği okla</span><span>🎥 Oto kamera</span><span>📊 Canlı istatistik</span>
|
||||
</div>
|
||||
<button id="startBtn">▶ BAŞLAT</button>
|
||||
<div class="keys">boşluk = oynat/durdur · ← → = 5 sn · fare = kamera · kişiye tıkla = sözleri</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="loadErr" style="display:none;position:fixed;inset:0;z-index:999;background:#0a0e14;color:#e8edf4;
|
||||
font-family:'Segoe UI',system-ui,sans-serif;align-items:center;justify-content:center;text-align:center;padding:24px">
|
||||
<div>
|
||||
<div style="font-size:15px;font-weight:600;margin-bottom:8px">⚠️ Bir dosya yüklenemedi</div>
|
||||
<div id="loadErrMsg" style="font-size:13px;color:#8b949e"></div>
|
||||
<div style="font-size:12px;color:#8b949e;margin-top:10px">Sayfayı yeniden yüklemeyi deneyin veya bir yerel sunucu üzerinden açın (file:// kısıtlamaları olabilir).</div>
|
||||
<div id="loadErrMsg" style="font-size:13px;color:#8b95a6"></div>
|
||||
<div style="font-size:12px;color:#8b95a6;margin-top:10px">Sayfayı yeniden yüklemeyi deneyin.</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
@@ -94,14 +179,14 @@ function showLoadErr(msg){
|
||||
if(m)m.textContent=msg; if(box){box.style.display='flex';}
|
||||
}
|
||||
</script>
|
||||
<audio id="ao" src="toplanti_orijinal.mp3?v=20260704d" preload="metadata" onerror="showLoadErr('toplanti_orijinal.mp3 yüklenemedi')"></audio>
|
||||
<audio id="at" preload="metadata" onerror="window.TR_AUDIO_FAILED=true"></audio>
|
||||
<audio id="ao" src="toplanti_orijinal.mp3?v=20260707a" preload="metadata" onerror="showLoadErr('toplanti_orijinal.mp3 yüklenemedi')"></audio>
|
||||
<audio id="at" preload="metadata" onerror="window.TR_AUDIO_FAILED=true;try{this.pause();}catch(e){}"></audio>
|
||||
|
||||
<script src="three.min.js?v=20260704d" onerror="showLoadErr('three.min.js (3D motoru) yüklenemedi')"></script>
|
||||
<script src="OrbitControls.js?v=20260704d" onerror="showLoadErr('OrbitControls.js (kamera kontrolü) yüklenemedi')"></script>
|
||||
<script src="data.js?v=20260704d" onerror="showLoadErr('data.js (toplantı verisi) yüklenemedi')"></script>
|
||||
<script src="three.min.js?v=20260704f" onerror="showLoadErr('three.min.js (3D motoru) yüklenemedi')"></script>
|
||||
<script src="OrbitControls.js?v=20260704f" onerror="showLoadErr('OrbitControls.js (kamera kontrolü) yüklenemedi')"></script>
|
||||
<script src="data.js?v=20260707b" onerror="showLoadErr('data.js (toplantı verisi) yüklenemedi')"></script>
|
||||
<script>
|
||||
if(typeof MEET==='undefined'){ showLoadErr('data.js yüklenemedi veya bozuk (MEET tanımsız)'); throw new Error('MEET tanımsız — data.js yüklenemedi'); }
|
||||
if(typeof MEET==='undefined'){ showLoadErr('data.js yüklenemedi veya bozuk'); throw new Error('MEET tanımsız'); }
|
||||
const ROLES=MEET.roles, TL=MEET.TL;
|
||||
const POS3D={
|
||||
"Kaan":{x:-1.6,z:2.3,stand:false}, "Marissa":{x:1.6,z:2.3,stand:false},
|
||||
@@ -109,56 +194,154 @@ const POS3D={
|
||||
"Yaşlı adam (V)":{x:-3.7,z:0,stand:false}, "Lider Uzlaşmacı (L.U)":{x:3.7,z:0,stand:false},
|
||||
"Kayınvalide":{x:3.3,z:-2.6,stand:true}
|
||||
};
|
||||
const SHORT={"Kaan":"Kaan","Marissa":"Marissa","Dolandırıcı (D-)":"Scammer Litoy","Uzlaşmacı (U)":"Kuya 2",
|
||||
"Yaşlı adam (V)":"Manong","Lider Uzlaşmacı (L.U)":"Kuya 1","Kayınvalide":"Daisy ⬆"};
|
||||
const SHORT={"Kaan":"Kaan","Marissa":"Marissa","Dolandırıcı (D-)":"Scammer Litoy","Uzlaşmacı (U)":"Barangay Kuya 2",
|
||||
"Yaşlı adam (V)":"Manong","Lider Uzlaşmacı (L.U)":"Barangay Kuya 1","Kayınvalide":"Nanay Daisy"};
|
||||
const AVA={"Kaan":"K","Marissa":"M","Dolandırıcı (D-)":"L","Uzlaşmacı (U)":"K2",
|
||||
"Yaşlı adam (V)":"Mn","Lider Uzlaşmacı (L.U)":"K1","Kayınvalide":"ND"};
|
||||
const H2L={"Kaan":"Kaan","Marissa":"Marissa","Daisy":"Kayınvalide","Litoy":"Dolandırıcı (D-)",
|
||||
"Kuya1":"Lider Uzlaşmacı (L.U)","Kuya2":"Uzlaşmacı (U)","Manong":"Yaşlı adam (V)"};
|
||||
|
||||
function roundRect(g,x,y,w,h,r){g.beginPath();g.moveTo(x+r,y);g.arcTo(x+w,y,x+w,y+h,r);g.arcTo(x+w,y+h,x,y+h,r);g.arcTo(x,y+h,x,y,r);g.arcTo(x,y,x+w,y,r);g.closePath();}
|
||||
function makeLabel(text,color,scale){ scale=scale||1;
|
||||
const c=document.createElement('canvas'); c.width=256; c.height=64; const g=c.getContext('2d');
|
||||
g.fillStyle="rgba(13,17,23,0.85)"; roundRect(g,4,10,248,44,10); g.fill();
|
||||
g.fillStyle="rgba(10,14,20,0.88)"; roundRect(g,4,10,248,44,10); g.fill();
|
||||
g.strokeStyle=color; g.lineWidth=2; roundRect(g,4,10,248,44,10); g.stroke();
|
||||
g.fillStyle=color; g.font="bold 24px Segoe UI"; g.textAlign="center"; g.textBaseline="middle"; g.fillText(text,128,33);
|
||||
const spr=new THREE.Sprite(new THREE.SpriteMaterial({map:new THREE.CanvasTexture(c),transparent:true,depthTest:false}));
|
||||
spr.scale.set(1.9*scale,0.48*scale,1); return spr;
|
||||
const spr=new THREE.Sprite(new THREE.SpriteMaterial({map:new THREE.CanvasTexture(c),transparent:true,depthTest:false,sizeAttenuation:false}));
|
||||
spr.scale.set(0.115*scale,0.029*scale,1); return spr;
|
||||
}
|
||||
function woodTexture(base,stripe){
|
||||
const c=document.createElement('canvas'); c.width=256; c.height=256; const g=c.getContext('2d');
|
||||
g.fillStyle=base; g.fillRect(0,0,256,256);
|
||||
for(let i=0;i<40;i++){ g.strokeStyle='rgba(0,0,0,'+(0.04+Math.random()*0.08)+')'; g.lineWidth=1+Math.random()*3;
|
||||
g.beginPath(); const y=Math.random()*256; g.moveTo(0,y);
|
||||
g.bezierCurveTo(64,y+(Math.random()*8-4),192,y+(Math.random()*8-4),256,y); g.stroke(); }
|
||||
g.strokeStyle=stripe; g.lineWidth=1;
|
||||
for(let y=0;y<256;y+=32){ g.strokeRect(0,y,256,32); }
|
||||
const t=new THREE.CanvasTexture(c); t.wrapS=t.wrapT=THREE.RepeatWrapping; return t;
|
||||
}
|
||||
function windowTexture(){
|
||||
const c=document.createElement('canvas'); c.width=256; c.height=192; const g=c.getContext('2d');
|
||||
const gr=g.createLinearGradient(0,0,0,192); gr.addColorStop(0,'#0b1530'); gr.addColorStop(1,'#1a2a50');
|
||||
g.fillStyle=gr; g.fillRect(0,0,256,192);
|
||||
g.fillStyle='#dfe8ff'; g.beginPath(); g.arc(200,42,17,0,7); g.fill();
|
||||
g.fillStyle='rgba(223,232,255,0.25)'; g.beginPath(); g.arc(200,42,24,0,7); g.fill();
|
||||
for(let i=0;i<60;i++){ g.fillStyle='rgba(255,255,255,'+(0.3+Math.random()*0.7)+')';
|
||||
g.fillRect(Math.random()*256,Math.random()*120,1.4,1.4); }
|
||||
for(let i=0;i<14;i++){ const bx=10+i*18, bh=30+Math.random()*46;
|
||||
g.fillStyle='#0a1020'; g.fillRect(bx,192-bh,14,bh);
|
||||
g.fillStyle='#e8c56a'; for(let w=0;w<5;w++){ if(Math.random()<0.5) g.fillRect(bx+3+(w%2)*6,196-bh+4+Math.floor(w/2)*8,3,4); } }
|
||||
return new THREE.CanvasTexture(c);
|
||||
}
|
||||
|
||||
/* ================= SAHNE ================= */
|
||||
const scene=new THREE.Scene();
|
||||
scene.background=new THREE.Color(0x0d1117);
|
||||
scene.fog=new THREE.Fog(0x0d1117,16,34);
|
||||
scene.background=new THREE.Color(0x0a0e14);
|
||||
scene.fog=new THREE.Fog(0x0a0e14,22,44);
|
||||
const camera=new THREE.PerspectiveCamera(48,innerWidth/innerHeight,0.1,100);
|
||||
function fitCamera(){
|
||||
const narrow=innerWidth<700;
|
||||
camera.position.set(0, narrow?8.6:6.2, narrow?14.5:9.6);
|
||||
camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix();
|
||||
}
|
||||
fitCamera();
|
||||
function baseCamPos(){ const n=innerWidth<700; return new THREE.Vector3(0, n?8.6:6.2, n?14.5:9.6); }
|
||||
camera.position.copy(baseCamPos());
|
||||
const renderer=new THREE.WebGLRenderer({antialias:true});
|
||||
renderer.setSize(innerWidth,innerHeight); renderer.setPixelRatio(Math.min(devicePixelRatio,2));
|
||||
renderer.shadowMap.enabled=true; renderer.shadowMap.type=THREE.PCFSoftShadowMap;
|
||||
document.getElementById('scene').appendChild(renderer.domElement);
|
||||
const controls=new THREE.OrbitControls(camera,renderer.domElement);
|
||||
controls.enableDamping=true; controls.dampingFactor=0.08; controls.target.set(0,1,0);
|
||||
controls.maxPolarAngle=Math.PI*0.49; controls.minDistance=5; controls.maxDistance=22;
|
||||
controls.maxPolarAngle=Math.PI*0.49; controls.minDistance=4.5; controls.maxDistance=24;
|
||||
|
||||
scene.add(new THREE.AmbientLight(0xffffff,0.55));
|
||||
const key=new THREE.DirectionalLight(0xffffff,0.9); key.position.set(6,12,8); scene.add(key);
|
||||
const fill=new THREE.DirectionalLight(0x88aaff,0.35); fill.position.set(-8,6,-6); scene.add(fill);
|
||||
scene.add(new THREE.AmbientLight(0x8899bb,0.38));
|
||||
const key=new THREE.DirectionalLight(0xbfd4ff,0.35); key.position.set(6,12,8); scene.add(key);
|
||||
// tavan lambası + spot
|
||||
const lampSpot=new THREE.SpotLight(0xffe2b0,1.25,26,Math.PI/3.4,0.5,1.2);
|
||||
lampSpot.position.set(0,7.2,0); lampSpot.target.position.set(0,1,0);
|
||||
lampSpot.castShadow=true; lampSpot.shadow.mapSize.set(1024,1024); lampSpot.shadow.bias=-0.0015;
|
||||
scene.add(lampSpot); scene.add(lampSpot.target);
|
||||
const cord=new THREE.Mesh(new THREE.CylinderGeometry(0.02,0.02,1.6,6),new THREE.MeshBasicMaterial({color:0x222831}));
|
||||
cord.position.set(0,7.0,0); scene.add(cord);
|
||||
const shade=new THREE.Mesh(new THREE.ConeGeometry(0.75,0.55,24,1,true),
|
||||
new THREE.MeshStandardMaterial({color:0x2a3242,side:THREE.DoubleSide,emissive:0x110c02}));
|
||||
shade.position.set(0,6.2,0); scene.add(shade);
|
||||
const bulbL=new THREE.Mesh(new THREE.SphereGeometry(0.14,12,12),
|
||||
new THREE.MeshStandardMaterial({color:0xfff3cf,emissive:0xffd88a,emissiveIntensity:1.8}));
|
||||
bulbL.position.set(0,6.05,0); scene.add(bulbL);
|
||||
|
||||
const floor=new THREE.Mesh(new THREE.PlaneGeometry(40,40),new THREE.MeshStandardMaterial({color:0x1c2230,roughness:0.95}));
|
||||
floor.rotation.x=-Math.PI/2; scene.add(floor);
|
||||
const rug=new THREE.Mesh(new THREE.CircleGeometry(7.5,48),new THREE.MeshStandardMaterial({color:0x232a3a,roughness:1}));
|
||||
rug.rotation.x=-Math.PI/2; rug.position.y=0.01; scene.add(rug);
|
||||
// zemin + halı
|
||||
const floor=new THREE.Mesh(new THREE.PlaneGeometry(40,40),
|
||||
new THREE.MeshStandardMaterial({map:woodTexture('#20242e','rgba(255,255,255,0.02)'),roughness:0.9}));
|
||||
floor.material.map.repeat.set(8,8);
|
||||
floor.rotation.x=-Math.PI/2; floor.receiveShadow=true; scene.add(floor);
|
||||
const rug=new THREE.Mesh(new THREE.CircleGeometry(7.2,48),new THREE.MeshStandardMaterial({color:0x232c40,roughness:1}));
|
||||
rug.rotation.x=-Math.PI/2; rug.position.y=0.012; rug.receiveShadow=true; scene.add(rug);
|
||||
|
||||
// duvarlar + pencere + tablo + bitki
|
||||
const wallMat=new THREE.MeshStandardMaterial({color:0x151b28,roughness:0.95});
|
||||
const wallB=new THREE.Mesh(new THREE.PlaneGeometry(24,5.2),wallMat); wallB.position.set(0,2.6,-7.5); scene.add(wallB);
|
||||
const wallL=new THREE.Mesh(new THREE.PlaneGeometry(20,5.2),wallMat); wallL.rotation.y=Math.PI/2; wallL.position.set(-9.5,2.6,0); scene.add(wallL);
|
||||
const wallR=new THREE.Mesh(new THREE.PlaneGeometry(20,5.2),wallMat); wallR.rotation.y=-Math.PI/2; wallR.position.set(9.5,2.6,0); scene.add(wallR);
|
||||
const winFrame=new THREE.Mesh(new THREE.BoxGeometry(4.6,2.6,0.12),new THREE.MeshStandardMaterial({color:0x39424f}));
|
||||
winFrame.position.set(-2.2,2.7,-7.44); scene.add(winFrame);
|
||||
const winGlass=new THREE.Mesh(new THREE.PlaneGeometry(4.2,2.2),
|
||||
new THREE.MeshBasicMaterial({map:windowTexture()}));
|
||||
winGlass.position.set(-2.2,2.7,-7.36); scene.add(winGlass);
|
||||
const winBar=new THREE.Mesh(new THREE.BoxGeometry(0.08,2.2,0.05),new THREE.MeshStandardMaterial({color:0x39424f}));
|
||||
winBar.position.set(-2.2,2.7,-7.34); scene.add(winBar);
|
||||
const pic=new THREE.Mesh(new THREE.PlaneGeometry(1.6,1.1),
|
||||
new THREE.MeshStandardMaterial({color:0x24405e,emissive:0x0a1522,roughness:0.6}));
|
||||
pic.rotation.y=-Math.PI/2; pic.position.set(9.44,2.8,-1); scene.add(pic);
|
||||
const picF=new THREE.Mesh(new THREE.BoxGeometry(0.06,1.3,1.8),new THREE.MeshStandardMaterial({color:0x4d4234}));
|
||||
picF.position.set(9.47,2.8,-1); scene.add(picF);
|
||||
const potM=new THREE.Mesh(new THREE.CylinderGeometry(0.32,0.24,0.5,12),new THREE.MeshStandardMaterial({color:0x6b4a2b}));
|
||||
potM.position.set(-7.6,0.25,-6.2); potM.castShadow=true; scene.add(potM);
|
||||
const plant=new THREE.Mesh(new THREE.ConeGeometry(0.75,1.9,10),new THREE.MeshStandardMaterial({color:0x2e5c37,roughness:0.9}));
|
||||
plant.position.set(-7.6,1.4,-6.2); plant.castShadow=true; scene.add(plant);
|
||||
|
||||
// masa
|
||||
const TABLE_H=1.0;
|
||||
const tableTop=new THREE.Mesh(new THREE.BoxGeometry(6.4,0.16,3.2),new THREE.MeshStandardMaterial({color:0x6b4a2b,roughness:0.6}));
|
||||
tableTop.position.y=TABLE_H; scene.add(tableTop);
|
||||
const tableTop=new THREE.Mesh(new THREE.BoxGeometry(6.4,0.16,3.2),
|
||||
new THREE.MeshStandardMaterial({map:woodTexture('#6b4a2b','rgba(0,0,0,0.06)'),roughness:0.55}));
|
||||
tableTop.position.y=TABLE_H; tableTop.castShadow=true; tableTop.receiveShadow=true; scene.add(tableTop);
|
||||
[[2.9,1.4],[-2.9,1.4],[2.9,-1.4],[-2.9,-1.4]].forEach(function(p){
|
||||
const leg=new THREE.Mesh(new THREE.CylinderGeometry(0.11,0.11,TABLE_H,12),new THREE.MeshStandardMaterial({color:0x4a3220}));
|
||||
leg.position.set(p[0],TABLE_H/2,p[1]); scene.add(leg);
|
||||
leg.position.set(p[0],TABLE_H/2,p[1]); leg.castShadow=true; scene.add(leg);
|
||||
});
|
||||
// kayıt cihazı (diyagramdaki yerinde: Kaan önü, masada)
|
||||
const rec=new THREE.Mesh(new THREE.BoxGeometry(0.5,0.12,0.28),
|
||||
new THREE.MeshStandardMaterial({color:0xd21f1f,emissive:0x550000,roughness:0.4}));
|
||||
rec.position.set(-1.3,TABLE_H+0.14,0.55); rec.castShadow=true; scene.add(rec);
|
||||
const recDot=new THREE.Mesh(new THREE.SphereGeometry(0.035,8,8),
|
||||
new THREE.MeshStandardMaterial({color:0xff3333,emissive:0xff0000,emissiveIntensity:2}));
|
||||
recDot.position.set(-1.45,TABLE_H+0.21,0.55); scene.add(recDot);
|
||||
// kupalar
|
||||
[[0.8,-0.8],[-2.5,-0.4],[2.6,0.7]].forEach(function(p){
|
||||
const mug=new THREE.Mesh(new THREE.CylinderGeometry(0.09,0.075,0.14,10),
|
||||
new THREE.MeshStandardMaterial({color:0xcfd6e2,roughness:0.4}));
|
||||
mug.position.set(p[0],TABLE_H+0.16,p[1]); mug.castShadow=true; scene.add(mug);
|
||||
});
|
||||
const rec=new THREE.Mesh(new THREE.BoxGeometry(0.5,0.12,0.28),new THREE.MeshStandardMaterial({color:0xd21f1f,emissive:0x330000,roughness:0.4}));
|
||||
rec.position.set(0,TABLE_H+0.14,0); scene.add(rec);
|
||||
const recLbl=makeLabel("🔴 KAYIT","#ff6666",0.55); recLbl.position.set(0,TABLE_H+0.55,0); scene.add(recLbl);
|
||||
|
||||
// sahte faturalar (tıklanabilir)
|
||||
const paperGroup=new THREE.Group();
|
||||
const paperMat=new THREE.MeshStandardMaterial({color:0xf2ede1,roughness:0.85});
|
||||
const paperLineMat=new THREE.MeshStandardMaterial({color:0xcfc8b8,roughness:0.9});
|
||||
const A5_W=0.42, A5_H=0.6, A5_T=0.006;
|
||||
for(let i=0;i<5;i++){
|
||||
const sheet=new THREE.Mesh(new THREE.BoxGeometry(A5_W,A5_T,A5_H),paperMat);
|
||||
sheet.position.set((Math.random()-0.5)*0.03,TABLE_H+0.08+i*(A5_T+0.001),(Math.random()-0.5)*0.03);
|
||||
sheet.rotation.y=(Math.random()-0.5)*0.28; sheet.castShadow=true;
|
||||
paperGroup.add(sheet);
|
||||
if(i===4){
|
||||
for(let l=0;l<4;l++){
|
||||
const line=new THREE.Mesh(new THREE.BoxGeometry(A5_W*0.72,0.001,0.012),paperLineMat);
|
||||
line.position.set(sheet.position.x,sheet.position.y+A5_T/2+0.001,sheet.position.z-A5_H*0.28+l*0.12);
|
||||
line.rotation.y=sheet.rotation.y;
|
||||
paperGroup.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
paperGroup.position.set(-0.5,0,1.15);
|
||||
scene.add(paperGroup);
|
||||
const paperLbl=makeLabel("📄 Faturalar","#e0b400",0.42); paperLbl.position.set(-0.5,TABLE_H+0.42,1.15); scene.add(paperLbl);
|
||||
|
||||
/* ---- karakterler ---- */
|
||||
const SKIN=0xe8b98c, chars={};
|
||||
function makeChar(role){
|
||||
const p=POS3D[role], col=new THREE.Color(ROLES[role].renk);
|
||||
@@ -175,9 +358,9 @@ function makeChar(role){
|
||||
const h=new THREE.Mesh(new THREE.SphereGeometry(0.205,18,18,0,Math.PI*2,0,Math.PI*0.62),hair); h.position.y=1.9; grp.add(h);
|
||||
headY=1.86;
|
||||
} else {
|
||||
const seat=new THREE.Mesh(new THREE.BoxGeometry(0.56,0.1,0.56),new THREE.MeshStandardMaterial({color:0x394150,roughness:0.8}));
|
||||
const seat=new THREE.Mesh(new THREE.BoxGeometry(0.56,0.1,0.56),new THREE.MeshStandardMaterial({color:0x353e50,roughness:0.8}));
|
||||
seat.position.set(0,0.5,-0.08); grp.add(seat);
|
||||
const back=new THREE.Mesh(new THREE.BoxGeometry(0.56,0.62,0.08),new THREE.MeshStandardMaterial({color:0x394150,roughness:0.8}));
|
||||
const back=new THREE.Mesh(new THREE.BoxGeometry(0.56,0.62,0.08),new THREE.MeshStandardMaterial({color:0x353e50,roughness:0.8}));
|
||||
back.position.set(0,0.8,-0.34); grp.add(back);
|
||||
const thigh=new THREE.Mesh(new THREE.BoxGeometry(0.34,0.14,0.42),cloth); thigh.position.set(0,0.6,0.14); grp.add(thigh);
|
||||
const shinL=new THREE.Mesh(new THREE.CylinderGeometry(0.08,0.08,0.5,10),cloth); shinL.position.set(-0.12,0.3,0.32); grp.add(shinL);
|
||||
@@ -187,49 +370,128 @@ function makeChar(role){
|
||||
const h=new THREE.Mesh(new THREE.SphereGeometry(0.2,18,18,0,Math.PI*2,0,Math.PI*0.6),hair); h.position.y=1.48; grp.add(h);
|
||||
headY=1.44;
|
||||
}
|
||||
const ring=new THREE.Mesh(new THREE.TorusGeometry(0.55,0.06,10,32),new THREE.MeshStandardMaterial({color:col,emissive:col,emissiveIntensity:1.4}));
|
||||
grp.traverse(function(o){ if(o.isMesh) o.castShadow=true; });
|
||||
const ring=new THREE.Mesh(new THREE.TorusGeometry(0.55,0.06,10,32),
|
||||
new THREE.MeshStandardMaterial({color:col,emissive:col,emissiveIntensity:1.4}));
|
||||
ring.rotation.x=-Math.PI/2; ring.position.y=0.04; ring.visible=false; grp.add(ring);
|
||||
// konuşan kişinin üstünde ampul + ışık
|
||||
const bulb=new THREE.Mesh(new THREE.SphereGeometry(0.1,16,16),new THREE.MeshStandardMaterial({color:0xfff6c0,emissive:0xffca28,emissiveIntensity:2.2}));
|
||||
const tring=new THREE.Mesh(new THREE.TorusGeometry(0.5,0.035,8,32),
|
||||
new THREE.MeshBasicMaterial({color:0xffffff,transparent:true,opacity:0.7}));
|
||||
tring.rotation.x=-Math.PI/2; tring.position.y=0.05; tring.visible=false; grp.add(tring);
|
||||
const bulb=new THREE.Mesh(new THREE.SphereGeometry(0.1,16,16),
|
||||
new THREE.MeshStandardMaterial({color:0xfff6c0,emissive:0xffca28,emissiveIntensity:2.2}));
|
||||
bulb.position.y=headY+1.05; bulb.visible=false; grp.add(bulb);
|
||||
const halo=new THREE.Mesh(new THREE.SphereGeometry(0.17,16,16),new THREE.MeshBasicMaterial({color:0xffd23a,transparent:true,opacity:0.25}));
|
||||
const halo=new THREE.Mesh(new THREE.SphereGeometry(0.17,16,16),
|
||||
new THREE.MeshBasicMaterial({color:0xffd23a,transparent:true,opacity:0.25}));
|
||||
halo.position.y=headY+1.05; halo.visible=false; grp.add(halo);
|
||||
const blight=new THREE.PointLight(0xffd23a,0,4,2); blight.position.set(0,headY+1.0,0); grp.add(blight);
|
||||
const lbl=makeLabel(SHORT[role],"#"+col.getHexString()); lbl.position.y=headY+0.55; grp.add(lbl);
|
||||
grp.position.set(p.x,0,p.z); grp.rotation.y=Math.atan2(-p.x,-p.z);
|
||||
scene.add(grp); chars[role]={grp:grp,ring:ring,bulb:bulb,halo:halo,blight:blight,active:false};
|
||||
grp.position.set(p.x,0,p.z);
|
||||
const baseY=Math.atan2(-p.x,-p.z);
|
||||
grp.rotation.y=baseY;
|
||||
scene.add(grp);
|
||||
chars[role]={grp:grp,ring:ring,tring:tring,bulb:bulb,halo:halo,blight:blight,active:false,
|
||||
headY:headY,baseY:baseY,phase:Math.random()*6};
|
||||
}
|
||||
Object.keys(POS3D).forEach(makeChar);
|
||||
|
||||
// ---- audio + timeline ----
|
||||
/* ---- konuşmacı -> hedef ışını ---- */
|
||||
let beam=null, beamDot=null, beamPair='';
|
||||
function clearBeam(){
|
||||
if(beam){ scene.remove(beam); beam.geometry.dispose(); beam.material.dispose(); beam=null; }
|
||||
if(beamDot){ scene.remove(beamDot); beamDot.geometry.dispose(); beamDot.material.dispose(); beamDot=null; }
|
||||
for(const r in chars) chars[r].tring.visible=false;
|
||||
beamPair='';
|
||||
}
|
||||
function setBeam(fromRole,toRole){
|
||||
const pairKey=fromRole+'>'+(toRole||'');
|
||||
if(pairKey===beamPair) return;
|
||||
clearBeam(); beamPair=pairKey;
|
||||
if(!fromRole||!toRole||!chars[toRole]||fromRole===toRole) return;
|
||||
const f=chars[fromRole], t=chars[toRole];
|
||||
const p1=new THREE.Vector3(POS3D[fromRole].x,f.headY+0.25,POS3D[fromRole].z);
|
||||
const p2=new THREE.Vector3(POS3D[toRole].x,t.headY+0.25,POS3D[toRole].z);
|
||||
const mid=p1.clone().add(p2).multiplyScalar(0.5); mid.y+=1.15+p1.distanceTo(p2)*0.12;
|
||||
const curve=new THREE.QuadraticBezierCurve3(p1,mid,p2);
|
||||
const col=new THREE.Color(ROLES[fromRole].renk);
|
||||
beam=new THREE.Mesh(new THREE.TubeGeometry(curve,32,0.022,6,false),
|
||||
new THREE.MeshBasicMaterial({color:col,transparent:true,opacity:0.4}));
|
||||
beam.userData.curve=curve; scene.add(beam);
|
||||
beamDot=new THREE.Mesh(new THREE.SphereGeometry(0.07,10,10),
|
||||
new THREE.MeshBasicMaterial({color:0xffffff}));
|
||||
scene.add(beamDot);
|
||||
t.tring.visible=true;
|
||||
}
|
||||
|
||||
/* ================= SES + ZAMAN ================= */
|
||||
const ao=document.getElementById('ao'), at=document.getElementById('at');
|
||||
let mode='orig';
|
||||
const TL_TR=MEET.TL_tr||null;
|
||||
if(MEET.trAudio){ at.src=MEET.trAudio+'?v=20260704d'; }
|
||||
if(MEET.trAudio){ at.src=MEET.trAudio+'?v=20260707a'; }
|
||||
function TR_READY(){ return !!MEET.trAudio && !!TL_TR && !window.TR_AUDIO_FAILED; }
|
||||
function A(){ return (mode==='tr'&&TR_READY())?at:ao; }
|
||||
function curTL(){ return (mode==='tr'&&TR_READY())?TL_TR:TL; }
|
||||
|
||||
/* ---- sol panel ---- */
|
||||
const GROUPS=[
|
||||
{ad:'🔵 Kaan tarafı', uyeler:[
|
||||
['Kaan','şikâyetçi'],['Marissa','eşi; fiyat & makbuz takibi'],['Kayınvalide','baş müzakereci']]},
|
||||
{ad:'⚖️ Arabulucular', uyeler:[
|
||||
['Lider Uzlaşmacı (L.U)','lider arabulucu'],['Uzlaşmacı (U)','sorgulayan']]},
|
||||
{ad:'🟡 Karşı taraf', uyeler:[
|
||||
['Dolandırıcı (D-)','suçlanan'],['Yaşlı adam (V)','usta; Litoy ile çalıştı']]}
|
||||
];
|
||||
const lr=document.getElementById('legendRows');
|
||||
Object.keys(POS3D).forEach(function(r){
|
||||
const d=document.createElement('div'); d.className='row';
|
||||
d.innerHTML='<span class="dot" style="background:'+ROLES[r].renk+'"></span>'+SHORT[r]+(POS3D[r].stand?' <span style="color:#8b949e">(ayakta)</span>':'');
|
||||
GROUPS.forEach(function(g){
|
||||
const h=document.createElement('div');
|
||||
h.style.cssText='margin-top:7px;font-weight:700;font-size:10.5px;color:#8b95a6;letter-spacing:.3px';
|
||||
h.textContent=g.ad; lr.appendChild(h);
|
||||
g.uyeler.forEach(function(u){
|
||||
const r=u[0], d=document.createElement('div'); d.className='row'; d.title=u[1]+' — tıkla: ilk sözüne git';
|
||||
d.innerHTML='<span class="dot" style="background:'+ROLES[r].renk+';color:'+ROLES[r].renk+'"></span>'+SHORT[r]
|
||||
+(POS3D[r].stand?' <span style="color:#8b95a6">(ayakta)</span>':'')
|
||||
+' <span class="desc" style="color:#8b95a6;font-size:10px">— '+u[1]+'</span>';
|
||||
d.onclick=function(){ const T=curTL(), b=T.find(function(x){return x.rol===r;});
|
||||
if(b){ A().currentTime=b.t; update(); } };
|
||||
lr.appendChild(d);
|
||||
});
|
||||
});
|
||||
|
||||
/* ---- skor paneli ---- */
|
||||
const statTotals={};
|
||||
TL.forEach(function(b){ const s=statTotals[b.rol]||(statTotals[b.rol]={sec:0,n:0});
|
||||
s.sec+=(b.e-b.t); s.n++; });
|
||||
const maxSec=Math.max.apply(null,Object.keys(statTotals).map(function(r){return statTotals[r].sec;}));
|
||||
const statEls={};
|
||||
const sr=document.getElementById('statRows');
|
||||
Object.keys(statTotals).sort(function(a,b){return statTotals[b].sec-statTotals[a].sec;}).forEach(function(r){
|
||||
const s=statTotals[r], d=document.createElement('div'); d.className='srow';
|
||||
const tot=Math.round(s.sec), mins=Math.floor(tot/60), secs=tot%60;
|
||||
d.innerHTML='<div class="nm"><span>'+SHORT[r]+'</span><span style="color:#8b95a6">'
|
||||
+mins+':'+String(secs).padStart(2,'0')+' · '+s.n+' söz</span></div>'
|
||||
+'<div class="bar"><div class="fill" style="width:'+(s.sec/maxSec*100).toFixed(0)+'%;background:'
|
||||
+ROLES[r].renk+';color:'+ROLES[r].renk+'"></div></div>';
|
||||
sr.appendChild(d); statEls[r]=d;
|
||||
});
|
||||
function statHighlight(role){ for(const r in statEls) statEls[r].classList.toggle('on',r===role); }
|
||||
|
||||
/* ---- zaman çizelgesi ---- */
|
||||
const tl=document.getElementById('tl'), tg=tl.getContext('2d');
|
||||
function curDur(){ const d=A().duration, T=curTL(); return (Number.isFinite(d)&&d>0) ? d : T[T.length-1].e; }
|
||||
function curDur(){ const d=A().duration, T=curTL(); return (Number.isFinite(d)&&d>0)?d:T[T.length-1].e; }
|
||||
function fitTL(){ tl.width=tl.clientWidth*devicePixelRatio; tl.height=34*devicePixelRatio; tg.setTransform(devicePixelRatio,0,0,devicePixelRatio,0,0); drawTL(); }
|
||||
function drawTL(){
|
||||
const T=curTL(), dur=curDur(), W=tl.clientWidth, H=34;
|
||||
tg.clearRect(0,0,W,H);
|
||||
tg.fillStyle="#21262d"; roundRect(tg,0,11,W,12,6); tg.fill();
|
||||
const T=curTL(), dur=curDur(), W=tl.clientWidth;
|
||||
tg.clearRect(0,0,W,34);
|
||||
tg.fillStyle="#161b26"; roundRect(tg,0,11,W,12,6); tg.fill();
|
||||
tg.globalAlpha=0.85;
|
||||
T.forEach(function(b){ const x=b.t/dur*W, w=Math.max(1,(b.e-b.t)/dur*W); tg.fillStyle=(ROLES[b.rol]&&ROLES[b.rol].renk)||"#888"; tg.fillRect(x,11,w,12); });
|
||||
T.forEach(function(b){ const x=b.t/dur*W, w=Math.max(1,(b.e-b.t)/dur*W);
|
||||
tg.fillStyle=(ROLES[b.rol]&&ROLES[b.rol].renk)||"#888"; tg.fillRect(x,11,w,12); });
|
||||
tg.globalAlpha=1;
|
||||
const ph=(A().currentTime/dur)*W; tg.fillStyle="#fff"; tg.fillRect(ph-1,6,2,22); tg.beginPath(); tg.arc(ph,6,4,0,7); tg.fill();
|
||||
const ph=(A().currentTime/dur)*W;
|
||||
tg.fillStyle="#fff"; tg.shadowColor="#fff"; tg.shadowBlur=6;
|
||||
tg.fillRect(ph-1,6,2,22); tg.beginPath(); tg.arc(ph,6,4,0,7); tg.fill(); tg.shadowBlur=0;
|
||||
}
|
||||
function seekAtClientX(clientX){ const r=tl.getBoundingClientRect(); const x=(clientX-r.left)/r.width; const a=A(); a.currentTime=Math.max(0,Math.min(1,x))*curDur(); update(); }
|
||||
function seekAtClientX(clientX){ const r=tl.getBoundingClientRect(); const x=(clientX-r.left)/r.width;
|
||||
const a=A(); a.currentTime=Math.max(0,Math.min(1,x))*curDur(); update(); }
|
||||
let drag=false;
|
||||
tl.addEventListener('mousedown',function(e){drag=true;seekAtClientX(e.clientX);});
|
||||
addEventListener('mousemove',function(e){if(drag)seekAtClientX(e.clientX);});
|
||||
@@ -237,6 +499,7 @@ addEventListener('mouseup',function(){drag=false;});
|
||||
tl.addEventListener('touchstart',function(e){drag=true;seekAtClientX(e.touches[0].clientX);e.preventDefault();},{passive:false});
|
||||
addEventListener('touchmove',function(e){if(drag){seekAtClientX(e.touches[0].clientX);e.preventDefault();}},{passive:false});
|
||||
addEventListener('touchend',function(){drag=false;});
|
||||
addEventListener('touchcancel',function(){drag=false;});
|
||||
|
||||
function curIndex(){
|
||||
const t=A().currentTime, T=curTL();
|
||||
@@ -245,19 +508,50 @@ function curIndex(){
|
||||
for(let i=0;i<T.length;i++){ if(T[i].t<=t) ans=i; else break; }
|
||||
return ans;
|
||||
}
|
||||
let lastRole=null;
|
||||
function highlight(role){ if(role===lastRole)return; lastRole=role; for(const r in chars){ const on=(r===role); chars[r].active=on; chars[r].ring.visible=on; chars[r].bulb.visible=on; chars[r].halo.visible=on; if(!on)chars[r].blight.intensity=0; } }
|
||||
|
||||
/* ---- vurgulama + diyalog ---- */
|
||||
let lastRole=null, speakerRole=null, targetRole=null;
|
||||
function highlight(role,target){
|
||||
speakerRole=role; targetRole=target||null;
|
||||
if(role) setBeam(role,targetRole); else clearBeam();
|
||||
statHighlight(role);
|
||||
if(role===lastRole) return; lastRole=role;
|
||||
for(const r in chars){ const on=(r===role); chars[r].active=on;
|
||||
chars[r].ring.visible=on; chars[r].bulb.visible=on; chars[r].halo.visible=on;
|
||||
if(!on)chars[r].blight.intensity=0; }
|
||||
}
|
||||
const fmt=function(s){s=Math.max(0,s|0);return String(s/60|0).padStart(2,'0')+':'+String(s%60).padStart(2,'0');};
|
||||
const sub=document.getElementById('subtitle'),sW=document.getElementById('subWho'),sO=document.getElementById('subOrig'),sT=document.getElementById('subTr');
|
||||
const dlg=document.getElementById('dlg'), dAva=document.getElementById('dlgAva'),
|
||||
dName=document.getElementById('dlgName'), dMain=document.getElementById('dlgMain'), dSub=document.getElementById('dlgSub');
|
||||
let twText='', twPos=0, twBlock=-1;
|
||||
function setDialog(b,i){
|
||||
const col=(ROLES[b.rol]&&ROLES[b.rol].renk)||'#fff';
|
||||
dAva.textContent=AVA[b.rol]||SHORT[b.rol].charAt(0);
|
||||
dAva.style.background=col; dAva.style.color='#0a0e14'; dAva.style.boxShadow='0 0 14px '+col;
|
||||
const hl=b.hedef&&H2L[b.hedef], hshort=hl?SHORT[hl]:(b.hedef==='Herkes'?'Herkese':null);
|
||||
dName.innerHTML='<span style="background:#21262d;border:1px solid '+col+';border-radius:6px;padding:1px 7px;margin-right:9px;color:#e6edf3;font-size:12px;font-weight:700">ID '+i+'</span>'
|
||||
+'<span style="color:'+col+'">'+SHORT[b.rol].toUpperCase()+'</span>'
|
||||
+(hshort?'<span class="arrow">➜</span><span class="target">'+hshort.toUpperCase()+'</span>':'')
|
||||
+((mode==='tr'&&!TR_READY())?' <span class="badge">ses hazırlanıyor</span>':'');
|
||||
const main=(mode==='tr')?b.tr:b.orig, sub=(mode==='tr')?b.orig:b.tr;
|
||||
if(i!==twBlock){ twBlock=i; twText=main; twPos=0; }
|
||||
dSub.textContent=sub;
|
||||
}
|
||||
function twTick(){
|
||||
if(twPos<twText.length){
|
||||
twPos=Math.min(twText.length,twPos+2);
|
||||
dMain.innerHTML=twText.slice(0,twPos).replace(/</g,'<')+(twPos<twText.length?'<span class="cursor"></span>':'');
|
||||
}
|
||||
}
|
||||
function update(){
|
||||
const a=A(), T=curTL(), dur=curDur();
|
||||
document.getElementById('time').textContent=fmt(a.currentTime)+' / '+fmt(dur);
|
||||
const i=curIndex();
|
||||
if(i>=0){ const b=T[i]; highlight(b.rol);
|
||||
let badge=(mode==='tr'&&!TR_READY())?' <span class="badge">ses hazırlanıyor</span>':'';
|
||||
sW.innerHTML=(SHORT[b.rol]||b.rol)+badge; sW.style.color=(ROLES[b.rol]&&ROLES[b.rol].renk)||'#fff';
|
||||
sO.textContent=b.orig; sT.textContent=b.tr; sub.style.opacity=1;
|
||||
} else { highlight(null); sub.style.opacity=.6; }
|
||||
if(i>=0){ const b=T[i];
|
||||
highlight(b.rol, b.hedef&&H2L[b.hedef]?H2L[b.hedef]:null);
|
||||
setDialog(b,i);
|
||||
dlg.style.opacity=1;
|
||||
} else { highlight(null,null); dlg.style.opacity=.6; }
|
||||
drawTL();
|
||||
}
|
||||
ao.addEventListener('timeupdate',function(){if(mode==='orig'||!TR_READY())update();});
|
||||
@@ -265,44 +559,141 @@ at.addEventListener('timeupdate',function(){if(mode==='tr'&&TR_READY())update();
|
||||
ao.addEventListener('loadedmetadata',function(){fitTL();update();});
|
||||
at.addEventListener('loadedmetadata',function(){if(mode==='tr')fitTL();});
|
||||
|
||||
/* ---- kontroller ---- */
|
||||
const playBtn=document.getElementById('play');
|
||||
playBtn.onclick=function(){ const a=A(); if(a.paused){a.play();playBtn.textContent='⏸';}else{a.pause();playBtn.textContent='▶';} };
|
||||
document.getElementById('prev').onclick=function(){ const T=curTL(); let i=curIndex(); const a=A(); if(i>0&&a.currentTime-T[i].t<0.4)i--; a.currentTime=T[Math.max(0,i)].t; update(); };
|
||||
document.getElementById('next').onclick=function(){ const T=curTL(); let i=curIndex(); const a=A(); a.currentTime=T[Math.min(T.length-1,i+1)].t; update(); };
|
||||
document.addEventListener('keydown',function(e){ if(e.code==='Space'){e.preventDefault();playBtn.onclick();} if(e.code==='ArrowRight')A().currentTime+=5; if(e.code==='ArrowLeft')A().currentTime-=5; });
|
||||
document.getElementById('prev').onclick=function(){ const T=curTL(); let i=curIndex(); const a=A();
|
||||
if(i>0&&a.currentTime-T[i].t<0.4)i--; a.currentTime=T[Math.max(0,i)].t; update(); };
|
||||
document.getElementById('next').onclick=function(){ const T=curTL(); let i=curIndex(); const a=A();
|
||||
a.currentTime=T[Math.min(T.length-1,i+1)].t; update(); };
|
||||
let started=false;
|
||||
document.addEventListener('keydown',function(e){
|
||||
if(!started) return;
|
||||
if(e.code==='Space'){e.preventDefault();playBtn.onclick();}
|
||||
if(e.code==='ArrowRight')A().currentTime+=5;
|
||||
if(e.code==='ArrowLeft')A().currentTime-=5; });
|
||||
[ao,at].forEach(function(a){ a.addEventListener('ended',function(){ playBtn.textContent='▶'; }); });
|
||||
|
||||
document.getElementById('langToggle').addEventListener('click',function(e){
|
||||
const btn=e.target.closest('button'); if(!btn)return; const m=btn.dataset.m; if(m===mode)return;
|
||||
[].forEach.call(e.currentTarget.children,function(b){ b.classList.toggle('on',b===btn); b.classList.toggle('trm',b===btn&&m==='tr'); });
|
||||
const wasPlaying=!A().paused; const idx=curIndex(); A().pause();
|
||||
mode=m; sub.classList.toggle('trmode',m==='tr');
|
||||
mode=m;
|
||||
const T=curTL(); const b=T[Math.max(0,idx)]; if(b)A().currentTime=b.t;
|
||||
fitTL(); update(); if(wasPlaying){A().play();playBtn.textContent='⏸';}
|
||||
twBlock=-1; fitTL(); update(); if(wasPlaying){A().play();playBtn.textContent='⏸';}
|
||||
});
|
||||
|
||||
renderer.domElement.addEventListener('dblclick',function(ev){
|
||||
/* ---- oto kamera ---- */
|
||||
let autoCam=true, autoPauseUntil=0, userInteracting=false;
|
||||
const camBtn=document.getElementById('camBtn');
|
||||
camBtn.onclick=function(){ autoCam=!autoCam; camBtn.classList.toggle('on',autoCam); };
|
||||
controls.addEventListener('start',function(){ userInteracting=true; autoPauseUntil=performance.now()+7000; });
|
||||
controls.addEventListener('end',function(){ userInteracting=false; autoPauseUntil=performance.now()+7000; });
|
||||
const camTargetPos=new THREE.Vector3();
|
||||
function autoCamTick(){
|
||||
if(!autoCam||userInteracting||performance.now()<autoPauseUntil) return;
|
||||
if(innerWidth<700) return;
|
||||
let want;
|
||||
if(speakerRole&&POS3D[speakerRole]){
|
||||
const p=POS3D[speakerRole];
|
||||
const d=Math.max(0.35,Math.hypot(p.x,p.z));
|
||||
const nx=-p.x/d, nz=-p.z/d;
|
||||
want=new THREE.Vector3(nx*8.8, 5.4, nz*8.8);
|
||||
if(Math.hypot(want.x-POS3D[speakerRole].x,want.z-POS3D[speakerRole].z)<5){ want.multiplyScalar(1.25); want.y=5.4; }
|
||||
} else want=baseCamPos();
|
||||
camTargetPos.copy(want);
|
||||
camera.position.lerp(camTargetPos,0.022);
|
||||
}
|
||||
|
||||
/* ---- tıklamalar: kişi -> sıradaki sözü, faturalar -> sayfa ---- */
|
||||
const roleNextIdx={};
|
||||
function linesForRole(role){ return curTL().filter(function(x){return x.rol===role;}); }
|
||||
function openFakeInvoicePage(){
|
||||
const w=window.open('','_blank');
|
||||
if(!w)return;
|
||||
w.document.title='Sahte Faturalar';
|
||||
w.document.body.style.cssText='background:#0d1117;color:#e6edf3;font-family:"Segoe UI",system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;text-align:center;font-size:22px;font-weight:600';
|
||||
w.document.body.textContent='Alper Tarafından Duzenlenen Sahte faturalar';
|
||||
}
|
||||
let downXY=null;
|
||||
renderer.domElement.addEventListener('pointerdown',function(ev){
|
||||
downXY=(ev.button===0&&ev.isPrimary)?[ev.clientX,ev.clientY]:null; });
|
||||
renderer.domElement.addEventListener('pointerup',function(ev){
|
||||
if(ev.button!==0||!ev.isPrimary||!downXY) return;
|
||||
const moved=Math.hypot(ev.clientX-downXY[0],ev.clientY-downXY[1]); downXY=null;
|
||||
if(moved>6) return; // sürükleme = kamera, tık değil
|
||||
const rc=new THREE.Raycaster(), m=new THREE.Vector2((ev.clientX/innerWidth)*2-1,-(ev.clientY/innerHeight)*2+1);
|
||||
rc.setFromCamera(m,camera);
|
||||
const gs=Object.keys(chars).map(function(r){return chars[r].grp;});
|
||||
const hit=rc.intersectObjects(gs,true)[0]; if(!hit)return;
|
||||
let g=hit.object; while(g.parent&&gs.indexOf(g)<0)g=g.parent;
|
||||
const role=Object.keys(chars).find(function(r){return chars[r].grp===g;});
|
||||
const T=curTL(), b=T.find(function(x){return x.rol===role;}); if(b){A().currentTime=b.t;update();}
|
||||
const clickable=Object.keys(chars).map(function(r){return chars[r].grp;}).concat([paperGroup]);
|
||||
const hit=rc.intersectObjects(clickable,true)[0]; if(!hit)return;
|
||||
let g=hit.object; while(g.parent&&clickable.indexOf(g)<0)g=g.parent;
|
||||
if(g===paperGroup){ openFakeInvoicePage(); return; }
|
||||
const role=Object.keys(chars).find(function(r){return chars[r].grp===g;}); if(!role)return;
|
||||
const lines=linesForRole(role); if(!lines.length)return;
|
||||
let idx=roleNextIdx[role]||0;
|
||||
if(idx>=lines.length)idx=0;
|
||||
const b=lines[idx]; const a=A();
|
||||
a.currentTime=Math.max(0,b.t-0.1);
|
||||
roleNextIdx[role]=idx+1;
|
||||
update(); a.play(); playBtn.textContent='⏸';
|
||||
});
|
||||
|
||||
/* ---- giriş ekranı ---- */
|
||||
document.getElementById('startBtn').onclick=function(){
|
||||
started=true;
|
||||
document.getElementById('intro').style.display='none';
|
||||
fitTL(); update();
|
||||
A().play(); playBtn.textContent='⏸';
|
||||
};
|
||||
|
||||
/* ---- animasyon döngüsü ---- */
|
||||
let frame=0;
|
||||
function loop(){
|
||||
requestAnimationFrame(loop);
|
||||
const t=performance.now()/1000;
|
||||
const t=performance.now()/1000; frame++;
|
||||
for(const r in chars){ const c=chars[r];
|
||||
if(c.active){ c.grp.position.y=Math.sin(t*4)*0.04; c.ring.rotation.z+=0.02; c.ring.material.emissiveIntensity=1.1+Math.sin(t*6)*0.5;
|
||||
// nefes alma
|
||||
const breathe=Math.sin(t*1.4+c.phase)*0.008;
|
||||
if(c.active){
|
||||
c.grp.position.y=Math.sin(t*4)*0.04;
|
||||
c.ring.rotation.z+=0.02; c.ring.material.emissiveIntensity=1.1+Math.sin(t*6)*0.5;
|
||||
c.bulb.material.emissiveIntensity=1.6+Math.sin(t*6)*0.9; c.blight.intensity=1.4+Math.sin(t*6)*0.9;
|
||||
c.halo.material.opacity=0.22+Math.sin(t*6)*0.12; c.halo.scale.setScalar(1+Math.sin(t*6)*0.12); }
|
||||
else if(c.grp.position.y!==0){ c.grp.position.y*=0.85; if(Math.abs(c.grp.position.y)<0.002)c.grp.position.y=0; }
|
||||
c.halo.material.opacity=0.22+Math.sin(t*6)*0.12; c.halo.scale.setScalar(1+Math.sin(t*6)*0.12);
|
||||
} else {
|
||||
c.grp.position.y=c.grp.position.y*0.85+breathe*0.15;
|
||||
}
|
||||
// baş çevirme: konuşana (veya konuşmacı hedefe) bak
|
||||
let lookAt=null;
|
||||
if(speakerRole&&r===speakerRole&&targetRole&&POS3D[targetRole]) lookAt=POS3D[targetRole];
|
||||
else if(speakerRole&&r!==speakerRole&&POS3D[speakerRole]) lookAt=POS3D[speakerRole];
|
||||
let desired=c.baseY;
|
||||
if(lookAt){
|
||||
const dx=lookAt.x-POS3D[r].x, dz=lookAt.z-POS3D[r].z;
|
||||
let want=Math.atan2(dx,dz);
|
||||
let diff=want-c.baseY;
|
||||
while(diff>Math.PI)diff-=2*Math.PI; while(diff<-Math.PI)diff+=2*Math.PI;
|
||||
desired=c.baseY+Math.max(-0.45,Math.min(0.45,diff));
|
||||
}
|
||||
let dy=desired-c.grp.rotation.y;
|
||||
while(dy>Math.PI)dy-=2*Math.PI; while(dy<-Math.PI)dy+=2*Math.PI;
|
||||
c.grp.rotation.y+=dy*0.06;
|
||||
}
|
||||
if(beam&&beamDot){
|
||||
const tt=(t*0.55)%1;
|
||||
beamDot.position.copy(beam.userData.curve.getPointAt(tt));
|
||||
beam.material.opacity=0.3+Math.sin(t*5)*0.12;
|
||||
}
|
||||
recDot.material.emissiveIntensity=1.2+Math.sin(t*3.5)*0.9;
|
||||
if(frame%2===0) twTick();
|
||||
autoCamTick();
|
||||
controls.update(); renderer.render(scene,camera);
|
||||
}
|
||||
loop();
|
||||
addEventListener('resize',function(){ fitCamera(); renderer.setSize(innerWidth,innerHeight); fitTL(); });
|
||||
addEventListener('resize',function(){ camera.aspect=innerWidth/innerHeight; camera.updateProjectionMatrix();
|
||||
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
|
||||
renderer.setSize(innerWidth,innerHeight);
|
||||
if(innerWidth<700) camera.position.copy(baseCamPos());
|
||||
fitTL(); });
|
||||
fitTL();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user