Deepfake Authenticator commited on
Commit Β·
bb8ac90
1
Parent(s): da69892
feat: cinematic UI redesign
Browse files- Animated particle canvas background (60 connected floating dots)
- Glassmorphism cards with backdrop blur
- Space Grotesk + JetBrains Mono typography
- Animated SVG eye logo with rotating scan arc
- Orbiting ring animation on upload icon
- Shimmer sweep on active analyze button
- Radar sonar loading animation (3 rings + sweep)
- Glitch text animation on FAKE verdict
- Pulsing verdict badge (red/green)
- Gradient confidence bar with glow
- Risk pill badge (LOW/MEDIUM/CRITICAL)
- Slide-in insight cards with colored left border
- Frame timeline with hover tooltips
- Hero section with gradient headline + stat pills
- frontend/index.html +315 -490
- frontend/script.js +197 -144
frontend/index.html
CHANGED
|
@@ -1,552 +1,377 @@
|
|
| 1 |
-
<!DOCTYPE html>
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
--card2: #13131f;
|
| 18 |
-
--border: #1e1e30;
|
| 19 |
-
--text: #e2e8f0;
|
| 20 |
-
--muted: #64748b;
|
| 21 |
-
}
|
| 22 |
-
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
| 23 |
-
|
| 24 |
-
body {
|
| 25 |
-
background: var(--bg);
|
| 26 |
-
font-family: 'JetBrains Mono', monospace;
|
| 27 |
-
color: var(--text);
|
| 28 |
-
min-height: 100vh;
|
| 29 |
-
background-image:
|
| 30 |
-
radial-gradient(ellipse 80% 50% at 50% -20%, #00ff8808 0%, transparent 60%),
|
| 31 |
-
linear-gradient(var(--border) 1px, transparent 1px),
|
| 32 |
-
linear-gradient(90deg, var(--border) 1px, transparent 1px);
|
| 33 |
-
background-size: 100% 100%, 44px 44px, 44px 44px;
|
| 34 |
-
}
|
| 35 |
-
|
| 36 |
-
/* ββ Scrollbar ββ */
|
| 37 |
-
::-webkit-scrollbar { width: 4px; height: 4px; }
|
| 38 |
-
::-webkit-scrollbar-track { background: var(--bg); }
|
| 39 |
-
::-webkit-scrollbar-thumb { background: #00ff8833; border-radius: 4px; }
|
| 40 |
-
|
| 41 |
-
/* ββ Utilities ββ */
|
| 42 |
-
.neon { color: var(--neon); text-shadow: 0 0 12px #00ff8855; }
|
| 43 |
-
.red { color: var(--red); text-shadow: 0 0 12px #ff444455; }
|
| 44 |
-
.hidden { display: none !important; }
|
| 45 |
-
|
| 46 |
-
/* ββ Scanner ββ */
|
| 47 |
-
.scanner {
|
| 48 |
-
position: fixed; inset: 0; pointer-events: none; z-index: 100;
|
| 49 |
-
background: linear-gradient(to bottom,
|
| 50 |
-
transparent 0%, transparent 49.9%,
|
| 51 |
-
#00ff8806 50%, transparent 50.1%);
|
| 52 |
-
background-size: 100% 4px;
|
| 53 |
-
animation: scanMove 8s linear infinite;
|
| 54 |
-
}
|
| 55 |
-
@keyframes scanMove {
|
| 56 |
-
0% { background-position: 0 0; }
|
| 57 |
-
100% { background-position: 0 100vh; }
|
| 58 |
-
}
|
| 59 |
-
|
| 60 |
-
/* ββ Header ββ */
|
| 61 |
-
.header {
|
| 62 |
-
position: sticky; top: 0; z-index: 50;
|
| 63 |
-
background: #080810ee;
|
| 64 |
-
backdrop-filter: blur(12px);
|
| 65 |
-
border-bottom: 1px solid var(--border);
|
| 66 |
-
}
|
| 67 |
-
|
| 68 |
-
/* ββ Cards ββ */
|
| 69 |
-
.card {
|
| 70 |
-
background: var(--card);
|
| 71 |
-
border: 1px solid var(--border);
|
| 72 |
-
border-radius: 14px;
|
| 73 |
-
}
|
| 74 |
-
.card-inner {
|
| 75 |
-
background: var(--card2);
|
| 76 |
-
border: 1px solid var(--border);
|
| 77 |
-
border-radius: 10px;
|
| 78 |
-
}
|
| 79 |
-
|
| 80 |
-
/* ββ Upload zone ββ */
|
| 81 |
-
#dropZone {
|
| 82 |
-
border: 2px dashed #00ff8830;
|
| 83 |
-
border-radius: 12px;
|
| 84 |
-
cursor: pointer;
|
| 85 |
-
transition: all .25s ease;
|
| 86 |
-
min-height: 160px;
|
| 87 |
-
display: flex; align-items: center; justify-content: center;
|
| 88 |
-
}
|
| 89 |
-
#dropZone:hover, #dropZone.drag-over {
|
| 90 |
-
border-color: var(--neon);
|
| 91 |
-
background: #00ff8806;
|
| 92 |
-
box-shadow: 0 0 40px #00ff8812, inset 0 0 40px #00ff8806;
|
| 93 |
-
}
|
| 94 |
-
|
| 95 |
-
/* ββ Analyze button ββ */
|
| 96 |
-
#analyzeBtn {
|
| 97 |
-
background: transparent;
|
| 98 |
-
border: 1px solid #00ff8830;
|
| 99 |
-
color: #00ff8855;
|
| 100 |
-
border-radius: 8px;
|
| 101 |
-
padding: 12px 36px;
|
| 102 |
-
font-family: inherit;
|
| 103 |
-
font-weight: 700;
|
| 104 |
-
font-size: 13px;
|
| 105 |
-
letter-spacing: .15em;
|
| 106 |
-
cursor: not-allowed;
|
| 107 |
-
transition: all .25s ease;
|
| 108 |
-
}
|
| 109 |
-
#analyzeBtn.active {
|
| 110 |
-
border-color: var(--neon);
|
| 111 |
-
color: var(--neon);
|
| 112 |
-
cursor: pointer;
|
| 113 |
-
box-shadow: 0 0 20px #00ff8820;
|
| 114 |
-
}
|
| 115 |
-
#analyzeBtn.active:hover {
|
| 116 |
-
background: #00ff8810;
|
| 117 |
-
box-shadow: 0 0 30px #00ff8835;
|
| 118 |
-
transform: translateY(-1px);
|
| 119 |
-
}
|
| 120 |
-
#analyzeBtn:disabled { opacity: .45; cursor: not-allowed; transform: none !important; }
|
| 121 |
-
|
| 122 |
-
/* ββ Progress bar ββ */
|
| 123 |
-
.prog-track {
|
| 124 |
-
height: 3px; background: var(--border); border-radius: 99px; overflow: hidden;
|
| 125 |
-
}
|
| 126 |
-
.prog-fill {
|
| 127 |
-
height: 100%; border-radius: 99px;
|
| 128 |
-
background: linear-gradient(90deg, var(--neon), var(--neon-dim));
|
| 129 |
-
box-shadow: 0 0 8px var(--neon);
|
| 130 |
-
transition: width .4s ease;
|
| 131 |
-
}
|
| 132 |
-
|
| 133 |
-
/* ββ Verdict card ββ */
|
| 134 |
-
#verdictCard {
|
| 135 |
-
border-radius: 14px;
|
| 136 |
-
border: 2px solid var(--border);
|
| 137 |
-
background: var(--card);
|
| 138 |
-
transition: border-color .5s, box-shadow .5s;
|
| 139 |
-
}
|
| 140 |
-
#verdictCard.fake {
|
| 141 |
-
border-color: var(--red);
|
| 142 |
-
box-shadow: 0 0 50px #ff444418, inset 0 0 60px #ff44440a;
|
| 143 |
-
}
|
| 144 |
-
#verdictCard.real {
|
| 145 |
-
border-color: var(--neon);
|
| 146 |
-
box-shadow: 0 0 50px #00ff8818, inset 0 0 60px #00ff880a;
|
| 147 |
-
}
|
| 148 |
-
|
| 149 |
-
/* ββ Verdict badge ββ */
|
| 150 |
-
.verdict-badge {
|
| 151 |
-
width: 96px; height: 96px; border-radius: 50%;
|
| 152 |
-
border: 2px solid var(--border);
|
| 153 |
-
display: flex; align-items: center; justify-content: center;
|
| 154 |
-
font-size: 2.5rem;
|
| 155 |
-
transition: all .5s;
|
| 156 |
-
}
|
| 157 |
-
.verdict-badge.fake {
|
| 158 |
-
border-color: var(--red);
|
| 159 |
-
box-shadow: 0 0 30px #ff444440;
|
| 160 |
-
animation: pulseFake 2s ease-in-out infinite;
|
| 161 |
-
}
|
| 162 |
-
.verdict-badge.real {
|
| 163 |
-
border-color: var(--neon);
|
| 164 |
-
box-shadow: 0 0 30px #00ff8840;
|
| 165 |
-
animation: pulseReal 2s ease-in-out infinite;
|
| 166 |
-
}
|
| 167 |
-
@keyframes pulseFake {
|
| 168 |
-
0%,100% { box-shadow: 0 0 20px #ff444430; }
|
| 169 |
-
50% { box-shadow: 0 0 45px #ff444460; }
|
| 170 |
-
}
|
| 171 |
-
@keyframes pulseReal {
|
| 172 |
-
0%,100% { box-shadow: 0 0 20px #00ff8830; }
|
| 173 |
-
50% { box-shadow: 0 0 45px #00ff8860; }
|
| 174 |
-
}
|
| 175 |
-
|
| 176 |
-
/* ββ Confidence bar ββ */
|
| 177 |
-
.conf-track {
|
| 178 |
-
height: 10px; background: var(--border); border-radius: 99px; overflow: hidden;
|
| 179 |
-
}
|
| 180 |
-
.conf-fill {
|
| 181 |
-
height: 100%; border-radius: 99px;
|
| 182 |
-
transition: width 1.2s cubic-bezier(.22,1,.36,1);
|
| 183 |
-
}
|
| 184 |
-
.conf-fill.fake {
|
| 185 |
-
background: linear-gradient(90deg, #ff2222, #ff6666);
|
| 186 |
-
box-shadow: 0 0 12px #ff444466;
|
| 187 |
-
}
|
| 188 |
-
.conf-fill.real {
|
| 189 |
-
background: linear-gradient(90deg, var(--neon), var(--neon-dim));
|
| 190 |
-
box-shadow: 0 0 12px #00ff8866;
|
| 191 |
-
}
|
| 192 |
-
|
| 193 |
-
/* ββ Risk meter ββ */
|
| 194 |
-
.risk-meter {
|
| 195 |
-
position: relative; height: 8px; border-radius: 99px; overflow: hidden;
|
| 196 |
-
background: linear-gradient(90deg, #00ff88, #ffcc00, #ff4444);
|
| 197 |
-
}
|
| 198 |
-
.risk-needle {
|
| 199 |
-
position: absolute; top: -4px;
|
| 200 |
-
width: 3px; height: 16px; border-radius: 2px;
|
| 201 |
-
background: white;
|
| 202 |
-
box-shadow: 0 0 6px white;
|
| 203 |
-
transition: left 1.2s cubic-bezier(.22,1,.36,1);
|
| 204 |
-
transform: translateX(-50%);
|
| 205 |
-
}
|
| 206 |
-
|
| 207 |
-
/* ββ Insight items ββ */
|
| 208 |
-
.insight-item {
|
| 209 |
-
display: flex; align-items: flex-start; gap: 10px;
|
| 210 |
-
padding: 10px 12px; border-radius: 8px;
|
| 211 |
-
background: var(--card2);
|
| 212 |
-
border: 1px solid var(--border);
|
| 213 |
-
font-size: 12px; line-height: 1.5; color: #94a3b8;
|
| 214 |
-
animation: slideIn .3s ease both;
|
| 215 |
-
}
|
| 216 |
-
.insight-item .dot {
|
| 217 |
-
flex-shrink: 0; width: 6px; height: 6px; border-radius: 50%; margin-top: 5px;
|
| 218 |
-
}
|
| 219 |
-
@keyframes slideIn {
|
| 220 |
-
from { opacity:0; transform: translateX(-8px); }
|
| 221 |
-
to { opacity:1; transform: none; }
|
| 222 |
-
}
|
| 223 |
-
|
| 224 |
-
/* ββ Meta rows ββ */
|
| 225 |
-
.meta-row {
|
| 226 |
-
display: flex; justify-content: space-between; align-items: center;
|
| 227 |
-
padding: 7px 0;
|
| 228 |
-
border-bottom: 1px solid var(--border);
|
| 229 |
-
font-size: 12px;
|
| 230 |
-
}
|
| 231 |
-
.meta-row:last-child { border-bottom: none; }
|
| 232 |
-
.meta-key { color: var(--muted); letter-spacing: .05em; }
|
| 233 |
-
.meta-val { color: var(--text); font-weight: 600; }
|
| 234 |
-
|
| 235 |
-
/* ββ Timeline ββ */
|
| 236 |
-
#timelineChart {
|
| 237 |
-
display: flex; align-items: flex-end; gap: 3px;
|
| 238 |
-
height: 80px; overflow-x: auto; padding-bottom: 2px;
|
| 239 |
-
position: relative;
|
| 240 |
-
}
|
| 241 |
-
.t-bar {
|
| 242 |
-
flex-shrink: 0; width: 10px; border-radius: 3px 3px 0 0;
|
| 243 |
-
transition: opacity .3s, transform .2s;
|
| 244 |
-
cursor: pointer;
|
| 245 |
-
position: relative;
|
| 246 |
-
}
|
| 247 |
-
.t-bar:hover { transform: scaleY(1.08); filter: brightness(1.3); }
|
| 248 |
-
.t-bar .tooltip {
|
| 249 |
-
display: none; position: absolute; bottom: calc(100% + 6px); left: 50%;
|
| 250 |
-
transform: translateX(-50%);
|
| 251 |
-
background: #1e1e30; border: 1px solid var(--border);
|
| 252 |
-
color: var(--text); font-size: 10px; padding: 4px 7px; border-radius: 5px;
|
| 253 |
-
white-space: nowrap; z-index: 10; pointer-events: none;
|
| 254 |
-
}
|
| 255 |
-
.t-bar:hover .tooltip { display: block; }
|
| 256 |
-
.threshold-line {
|
| 257 |
-
position: absolute; left: 0; right: 0; height: 1px;
|
| 258 |
-
background: #facc1555; pointer-events: none;
|
| 259 |
-
}
|
| 260 |
-
|
| 261 |
-
/* ββ Agent steps ββ */
|
| 262 |
-
.agent-card {
|
| 263 |
-
border-radius: 10px; padding: 12px; text-align: center;
|
| 264 |
-
background: var(--card2); border: 1px solid var(--border);
|
| 265 |
-
transition: border-color .3s, background .3s, box-shadow .3s;
|
| 266 |
-
}
|
| 267 |
-
.agent-card.active {
|
| 268 |
-
border-color: #00ff8844;
|
| 269 |
-
background: #00ff8808;
|
| 270 |
-
box-shadow: 0 0 20px #00ff8810;
|
| 271 |
-
}
|
| 272 |
-
.agent-card .a-status { font-size: 10px; color: var(--muted); margin-top: 4px; }
|
| 273 |
-
.agent-card.active .a-status { color: var(--neon); }
|
| 274 |
-
|
| 275 |
-
/* ββ Fade/slide animations ββ */
|
| 276 |
-
.fade-up {
|
| 277 |
-
animation: fadeUp .45s ease both;
|
| 278 |
-
}
|
| 279 |
-
@keyframes fadeUp {
|
| 280 |
-
from { opacity:0; transform: translateY(16px); }
|
| 281 |
-
to { opacity:1; transform: none; }
|
| 282 |
-
}
|
| 283 |
-
|
| 284 |
-
/* ββ Section label ββ */
|
| 285 |
-
.sec-label {
|
| 286 |
-
font-size: 10px; font-weight: 700; letter-spacing: .12em;
|
| 287 |
-
color: var(--muted); display: flex; align-items: center; gap: 6px;
|
| 288 |
-
}
|
| 289 |
-
.sec-label::before {
|
| 290 |
-
content: ''; display: inline-block;
|
| 291 |
-
width: 6px; height: 6px; border-radius: 50%;
|
| 292 |
-
background: var(--neon); box-shadow: 0 0 6px var(--neon);
|
| 293 |
-
}
|
| 294 |
-
|
| 295 |
-
/* ββ Glow badge ββ */
|
| 296 |
-
#modelBadge {
|
| 297 |
-
font-size: 10px; padding: 4px 12px; border-radius: 99px;
|
| 298 |
-
border: 1px solid var(--border); color: var(--muted);
|
| 299 |
-
letter-spacing: .08em; transition: all .3s;
|
| 300 |
-
}
|
| 301 |
-
#modelBadge.ready {
|
| 302 |
-
border-color: #00ff8844; color: #00ff88aa;
|
| 303 |
-
box-shadow: 0 0 10px #00ff8815;
|
| 304 |
-
}
|
| 305 |
-
</style>
|
| 306 |
</head>
|
| 307 |
<body>
|
| 308 |
|
| 309 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
|
| 311 |
-
<
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
</svg>
|
| 322 |
</div>
|
| 323 |
<div>
|
| 324 |
-
<div style="font-size:
|
| 325 |
-
<div style="font-size:
|
| 326 |
</div>
|
| 327 |
</div>
|
| 328 |
-
<div id="modelBadge">
|
|
|
|
|
|
|
|
|
|
| 329 |
</div>
|
| 330 |
</header>
|
| 331 |
|
| 332 |
-
<!-- ββ MAIN ββ
|
| 333 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
|
| 335 |
-
<!--
|
| 336 |
-
<
|
| 337 |
<div id="dropZone">
|
| 338 |
-
<
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
<
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
|
|
|
|
|
|
|
|
|
| 345 |
</div>
|
| 346 |
-
<
|
| 347 |
-
<p style="font-size:
|
|
|
|
| 348 |
</div>
|
| 349 |
-
|
| 350 |
-
<div id="fileChosen" class="hidden" style="display:flex;align-items:center;gap:
|
| 351 |
-
<div style="width:
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
<rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"/>
|
| 355 |
-
<line x1="7" y1="2" x2="7" y2="22"/><line x1="17" y1="2" x2="17" y2="22"/>
|
| 356 |
-
<line x1="2" y1="12" x2="22" y2="12"/><line x1="2" y1="7" x2="7" y2="7"/>
|
| 357 |
-
<line x1="2" y1="17" x2="7" y2="17"/><line x1="17" y1="17" x2="22" y2="17"/>
|
| 358 |
-
<line x1="17" y1="7" x2="22" y2="7"/>
|
| 359 |
</svg>
|
| 360 |
</div>
|
| 361 |
<div style="flex:1;min-width:0;">
|
| 362 |
-
<p id="chosenName" style="font-size:
|
| 363 |
-
<p id="chosenSize" style="font-size:
|
| 364 |
</div>
|
| 365 |
-
<button id="clearBtn"
|
| 366 |
-
|
| 367 |
-
onmouseover="this.style.color='#ff4444'" onmouseout="this.style.color='var(--muted)'">
|
| 368 |
-
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
| 369 |
-
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
| 370 |
-
</svg>
|
| 371 |
</button>
|
| 372 |
</div>
|
| 373 |
</div>
|
| 374 |
-
|
| 375 |
-
<
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
<button id="analyzeBtn" type="button" disabled onclick="analyzeVideo()">
|
| 379 |
-
βΆ ANALYZE VIDEO
|
| 380 |
</button>
|
| 381 |
</div>
|
| 382 |
-
</
|
| 383 |
-
|
| 384 |
-
<!--
|
| 385 |
-
<
|
| 386 |
-
<
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
<
|
|
|
|
|
|
|
|
|
|
| 390 |
</div>
|
| 391 |
-
<
|
| 392 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 393 |
</div>
|
| 394 |
-
<
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
<div
|
| 398 |
-
<div
|
|
|
|
|
|
|
|
|
|
| 399 |
</div>
|
| 400 |
-
<div class="agent-card"
|
| 401 |
-
<div
|
| 402 |
-
<div style="
|
| 403 |
-
|
|
|
|
|
|
|
| 404 |
</div>
|
| 405 |
-
<div class="agent-card"
|
| 406 |
-
<div
|
| 407 |
-
<div style="
|
| 408 |
-
|
|
|
|
|
|
|
| 409 |
</div>
|
| 410 |
-
<div class="agent-card"
|
| 411 |
-
<div
|
| 412 |
-
<div style="
|
| 413 |
-
|
|
|
|
|
|
|
| 414 |
</div>
|
| 415 |
</div>
|
| 416 |
-
</
|
| 417 |
|
| 418 |
-
<!--
|
| 419 |
-
<
|
| 420 |
|
| 421 |
-
<!-- Verdict -->
|
| 422 |
-
<div id="verdictCard" style="padding:
|
| 423 |
-
<
|
| 424 |
-
|
| 425 |
-
<
|
| 426 |
-
|
| 427 |
-
<div id="verdictBadge" class="verdict-badge" style="margin:0 auto 10px;">
|
| 428 |
-
<span id="verdictEmoji"></span>
|
| 429 |
-
</div>
|
| 430 |
-
<div id="verdictLabel" style="font-size:28px;font-weight:700;letter-spacing:.15em;"></div>
|
| 431 |
-
<div style="font-size:10px;color:var(--muted);letter-spacing:.1em;margin-top:3px;">VERDICT</div>
|
| 432 |
</div>
|
| 433 |
-
|
| 434 |
-
<
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
</
|
| 440 |
-
<
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
</div>
|
| 452 |
-
<div style="display:flex;justify-content:space-between;margin-top:4px;">
|
| 453 |
-
<span style="font-size:9px;color:var(--muted);">LOW</span>
|
| 454 |
-
<span style="font-size:9px;color:var(--muted);">MEDIUM</span>
|
| 455 |
-
<span style="font-size:9px;color:var(--muted);">HIGH</span>
|
| 456 |
-
</div>
|
| 457 |
</div>
|
| 458 |
</div>
|
| 459 |
</div>
|
| 460 |
|
| 461 |
<!-- Insights + Meta -->
|
| 462 |
-
<div style="display:grid;grid-template-columns:1fr 1fr;gap:
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
<div
|
| 466 |
-
<div id="detailsList" style="display:flex;flex-direction:column;gap:8px;"></div>
|
| 467 |
</div>
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
<
|
| 474 |
-
|
| 475 |
-
<
|
| 476 |
-
<div style="font-size:10px;color:var(--muted);line-height:1.8;">
|
| 477 |
-
<div>π¬ dima806/deepfake_vs_real (99.3% acc)</div>
|
| 478 |
-
<div>π¬ prithivMLmods/Detector-v2 (92.1% acc)</div>
|
| 479 |
-
<div style="margin-top:4px;color:#00ff8877;">β‘ Weighted ensemble Β· ViT architecture</div>
|
| 480 |
-
</div>
|
| 481 |
</div>
|
| 482 |
</div>
|
| 483 |
</div>
|
| 484 |
|
| 485 |
<!-- Frame Timeline -->
|
| 486 |
-
<div class="
|
| 487 |
-
<div
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
</span>
|
| 493 |
-
<span style="display:flex;align-items:center;gap:5px;">
|
| 494 |
-
<span style="width:10px;height:10px;border-radius:2px;background:var(--red);display:inline-block;"></span>FAKE
|
| 495 |
-
</span>
|
| 496 |
-
<span style="display:flex;align-items:center;gap:5px;">
|
| 497 |
-
<span style="width:20px;height:1px;background:#facc1566;display:inline-block;"></span>60% THRESHOLD
|
| 498 |
-
</span>
|
| 499 |
-
</div>
|
| 500 |
</div>
|
| 501 |
-
<div id="timelineChart"></div>
|
| 502 |
</div>
|
| 503 |
|
| 504 |
-
<
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
border-radius:8px;cursor:pointer;transition:all .2s;"
|
| 509 |
-
onmouseover="this.style.borderColor='#00ff8844';this.style.color='var(--neon)'"
|
| 510 |
-
onmouseout="this.style.borderColor='var(--border)';this.style.color='var(--muted)'">
|
| 511 |
-
βΊ ANALYZE ANOTHER VIDEO
|
| 512 |
</button>
|
| 513 |
</div>
|
| 514 |
-
</
|
| 515 |
|
| 516 |
-
<!--
|
| 517 |
-
<
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
<span style="font-size:
|
| 521 |
-
<span style="color:var(--red);font-weight:700;font-size:13px;letter-spacing:.08em;">ANALYSIS FAILED</span>
|
| 522 |
</div>
|
| 523 |
-
<p id="errorMsg" style="font-size:
|
| 524 |
-
<
|
| 525 |
-
style="
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
βΊ Try again
|
| 529 |
-
</button>
|
| 530 |
-
</div>
|
| 531 |
|
| 532 |
-
</main>
|
| 533 |
|
| 534 |
-
<footer style="
|
| 535 |
-
|
| 536 |
-
DEEPFAKE AUTHENTICATOR Β· MEDIAPIPE + ENSEMBLE ViT Β· LOCAL INFERENCE
|
| 537 |
</footer>
|
| 538 |
|
| 539 |
-
<
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
}
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
}
|
| 548 |
-
</style>
|
| 549 |
-
|
| 550 |
<script src="script.js"></script>
|
| 551 |
</body>
|
| 552 |
-
</html>
|
|
|
|
| 1 |
+
ο»Ώ<!DOCTYPE html>
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
+
<meta charset="UTF-8"/>
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
| 6 |
+
<title>Deepfake Authenticator</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"/>
|
| 9 |
+
<style>
|
| 10 |
+
:root{--g:#00ff88;--r:#ff3355;--w:#ffaa00;--bg:#050508;--card:rgba(255,255,255,0.04);--border:rgba(0,255,136,0.18);--muted:#5a6a7a;}
|
| 11 |
+
*{box-sizing:border-box;margin:0;padding:0;}
|
| 12 |
+
body{background:var(--bg);font-family:'Space Grotesk',sans-serif;color:#e2e8f0;min-height:100vh;overflow-x:hidden;}
|
| 13 |
+
code,pre,.mono{font-family:'JetBrains Mono',monospace;}
|
| 14 |
+
::-webkit-scrollbar{width:5px;} ::-webkit-scrollbar-track{background:var(--bg);} ::-webkit-scrollbar-thumb{background:rgba(0,255,136,0.25);border-radius:4px;}
|
| 15 |
+
.hidden{display:none!important;}
|
| 16 |
+
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
</head>
|
| 18 |
<body>
|
| 19 |
|
| 20 |
+
<style>
|
| 21 |
+
/* ββ Particle Canvas ββ */
|
| 22 |
+
#particles{position:fixed;inset:0;z-index:0;pointer-events:none;}
|
| 23 |
+
/* ββ Grid overlay ββ */
|
| 24 |
+
.grid-bg{position:fixed;inset:0;z-index:0;pointer-events:none;
|
| 25 |
+
background-image:linear-gradient(rgba(0,255,136,0.03) 1px,transparent 1px),linear-gradient(90deg,rgba(0,255,136,0.03) 1px,transparent 1px);
|
| 26 |
+
background-size:60px 60px;}
|
| 27 |
+
/* ββ Glass ββ */
|
| 28 |
+
.glass{background:var(--card);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:16px;box-shadow:0 8px 40px rgba(0,0,0,0.5);}
|
| 29 |
+
.glass-sm{background:rgba(255,255,255,0.03);backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.07);border-radius:12px;}
|
| 30 |
+
/* ββ Glow borders ββ */
|
| 31 |
+
.glow-green{box-shadow:0 0 20px rgba(0,255,136,0.25),inset 0 0 20px rgba(0,255,136,0.04);}
|
| 32 |
+
.glow-red{box-shadow:0 0 20px rgba(255,51,85,0.25),inset 0 0 20px rgba(255,51,85,0.04);}
|
| 33 |
+
/* ββ Header ββ */
|
| 34 |
+
header{position:sticky;top:0;z-index:50;background:rgba(5,5,8,0.85);backdrop-filter:blur(24px);border-bottom:1px solid rgba(0,255,136,0.1);}
|
| 35 |
+
/* ββ Eye SVG animation ββ */
|
| 36 |
+
@keyframes scanPulse{0%,100%{opacity:1;transform:scale(1);}50%{opacity:0.5;transform:scale(1.15);}}
|
| 37 |
+
@keyframes eyeScan{0%{stroke-dashoffset:100;}100%{stroke-dashoffset:0;}}
|
| 38 |
+
.eye-scan{animation:scanPulse 2.5s ease-in-out infinite;}
|
| 39 |
+
/* ββ Status dot ββ */
|
| 40 |
+
@keyframes statusBlink{0%,100%{opacity:1;box-shadow:0 0 6px var(--g);}50%{opacity:0.4;box-shadow:none;}}
|
| 41 |
+
.status-dot{width:8px;height:8px;border-radius:50%;background:var(--g);animation:statusBlink 2s ease-in-out infinite;}
|
| 42 |
+
/* ββ Drop zone border animation ββ */
|
| 43 |
+
@keyframes borderDash{to{stroke-dashoffset:-20;}}
|
| 44 |
+
#dropZone{border:2px dashed rgba(0,255,136,0.25);border-radius:16px;cursor:pointer;min-height:200px;display:flex;align-items:center;justify-content:center;transition:all 0.35s ease;position:relative;overflow:hidden;}
|
| 45 |
+
#dropZone:hover,#dropZone.drag-over{border-color:var(--g);background:rgba(0,255,136,0.04);box-shadow:0 0 40px rgba(0,255,136,0.2),inset 0 0 30px rgba(0,255,136,0.06);transform:scale(1.01);}
|
| 46 |
+
/* ββ Orbit ring ββ */
|
| 47 |
+
@keyframes orbitRing{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}
|
| 48 |
+
.orbit{animation:orbitRing 3s linear infinite;transform-origin:center;}
|
| 49 |
+
/* ββ Analyze button ββ */
|
| 50 |
+
#analyzeBtn{width:100%;padding:16px;border-radius:12px;font-family:'Space Grotesk',sans-serif;font-weight:700;font-size:14px;letter-spacing:0.12em;text-transform:uppercase;border:1px solid rgba(255,255,255,0.1);background:rgba(255,255,255,0.05);color:var(--muted);cursor:not-allowed;transition:all 0.3s ease;position:relative;overflow:hidden;}
|
| 51 |
+
#analyzeBtn.active{background:linear-gradient(135deg,#00ff88,#00cc66);color:#050508;border-color:transparent;cursor:pointer;box-shadow:0 0 30px rgba(0,255,136,0.4);}
|
| 52 |
+
#analyzeBtn.active:hover{transform:translateY(-2px) scale(1.01);box-shadow:0 0 50px rgba(0,255,136,0.6);}
|
| 53 |
+
#analyzeBtn.active::after{content:'';position:absolute;top:0;left:-100%;width:60%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.25),transparent);animation:shimmer 2s ease infinite;}
|
| 54 |
+
@keyframes shimmer{to{left:150%;}}
|
| 55 |
+
#analyzeBtn:disabled{opacity:0.45;cursor:not-allowed;transform:none!important;}
|
| 56 |
+
</style>
|
| 57 |
|
| 58 |
+
<style>
|
| 59 |
+
/* ββ Loading ββ */
|
| 60 |
+
@keyframes radarSpin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}
|
| 61 |
+
@keyframes radarPulse{0%,100%{opacity:0.8;transform:scale(1);}50%{opacity:0.3;transform:scale(1.05);}}
|
| 62 |
+
.radar-ring{border-radius:50%;border:1px solid rgba(0,255,136,0.2);position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);}
|
| 63 |
+
.radar-sweep{position:absolute;top:50%;left:50%;width:50%;height:2px;transform-origin:left center;background:linear-gradient(90deg,transparent,var(--g));animation:radarSpin 2s linear infinite;}
|
| 64 |
+
/* ββ Agent cards ββ */
|
| 65 |
+
.agent-card{transition:all 0.4s ease;border:1px solid rgba(255,255,255,0.06);border-radius:12px;padding:12px 16px;background:rgba(255,255,255,0.02);}
|
| 66 |
+
.agent-card.active{border-color:var(--g);background:rgba(0,255,136,0.06);box-shadow:0 0 20px rgba(0,255,136,0.15);}
|
| 67 |
+
.agent-card.active .agent-dot{background:var(--g);box-shadow:0 0 8px var(--g);}
|
| 68 |
+
.agent-dot{width:8px;height:8px;border-radius:50%;background:rgba(255,255,255,0.15);transition:all 0.4s ease;flex-shrink:0;}
|
| 69 |
+
/* ββ Progress bar ββ */
|
| 70 |
+
.prog-track{height:4px;background:rgba(255,255,255,0.06);border-radius:99px;overflow:hidden;}
|
| 71 |
+
.prog-fill{height:100%;border-radius:99px;background:linear-gradient(90deg,#00aaff,var(--g));box-shadow:0 0 12px var(--g);transition:width 0.5s ease;}
|
| 72 |
+
/* ββ Verdict ββ */
|
| 73 |
+
@keyframes glitch{0%,100%{text-shadow:0 0 10px var(--r);}20%{text-shadow:-2px 0 #ff0,2px 0 #0ff,0 0 20px var(--r);}40%{text-shadow:2px 0 #ff0,-2px 0 #0ff,0 0 10px var(--r);}60%{text-shadow:0 0 30px var(--r);}}
|
| 74 |
+
.glitch-text{animation:glitch 3s ease-in-out infinite;}
|
| 75 |
+
@keyframes fadeUp{from{opacity:0;transform:translateY(24px);}to{opacity:1;transform:none;}}
|
| 76 |
+
.fade-up{animation:fadeUp 0.6s cubic-bezier(0.16,1,0.3,1) both;}
|
| 77 |
+
@keyframes slideInLeft{from{opacity:0;transform:translateX(-20px);}to{opacity:1;transform:none;}}
|
| 78 |
+
/* ββ Verdict badge ββ */
|
| 79 |
+
.verdict-badge{width:110px;height:110px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:2.8rem;transition:all 0.5s;border:2px solid var(--border);}
|
| 80 |
+
@keyframes pulseFake{0%,100%{box-shadow:0 0 20px rgba(255,51,85,0.3);}50%{box-shadow:0 0 50px rgba(255,51,85,0.7);}}
|
| 81 |
+
@keyframes pulseReal{0%,100%{box-shadow:0 0 20px rgba(0,255,136,0.3);}50%{box-shadow:0 0 50px rgba(0,255,136,0.7);}}
|
| 82 |
+
.verdict-badge.fake{border-color:var(--r);animation:pulseFake 2s infinite;}
|
| 83 |
+
.verdict-badge.real{border-color:var(--g);animation:pulseReal 2s infinite;}
|
| 84 |
+
/* ββ Confidence arc (CSS semicircle gauge) ββ */
|
| 85 |
+
.gauge-wrap{position:relative;width:200px;height:110px;overflow:hidden;margin:0 auto;}
|
| 86 |
+
.gauge-bg{width:200px;height:200px;border-radius:50%;border:12px solid rgba(255,255,255,0.06);position:absolute;top:0;left:0;clip-path:inset(0 0 50% 0);}
|
| 87 |
+
.gauge-fill{width:200px;height:200px;border-radius:50%;border:12px solid transparent;position:absolute;top:0;left:0;clip-path:inset(0 0 50% 0);transition:transform 1.2s cubic-bezier(0.22,1,0.36,1);}
|
| 88 |
+
.gauge-fill.fake{border-color:var(--r);box-shadow:0 0 20px rgba(255,51,85,0.5);}
|
| 89 |
+
.gauge-fill.real{border-color:var(--g);box-shadow:0 0 20px rgba(0,255,136,0.5);}
|
| 90 |
+
/* ββ Conf bar ββ */
|
| 91 |
+
.conf-track{height:10px;background:rgba(255,255,255,0.05);border-radius:99px;overflow:hidden;border:1px solid rgba(255,255,255,0.05);}
|
| 92 |
+
.conf-fill{height:100%;border-radius:99px;transition:width 1.2s cubic-bezier(0.22,1,0.36,1);}
|
| 93 |
+
.conf-fill.fake{background:linear-gradient(90deg,#880022,var(--r));box-shadow:0 0 15px rgba(255,51,85,0.6);}
|
| 94 |
+
.conf-fill.real{background:linear-gradient(90deg,#00aaff,var(--g));box-shadow:0 0 15px rgba(0,255,136,0.6);}
|
| 95 |
+
/* ββ Risk needle ββ */
|
| 96 |
+
#riskNeedle{display:inline-block;padding:4px 14px;border-radius:99px;font-size:11px;font-weight:700;letter-spacing:0.15em;border:1px solid;transition:all 0.5s;}
|
| 97 |
+
/* ββ Insight bullets ββ */
|
| 98 |
+
.insight-item{display:flex;align-items:flex-start;gap:12px;padding:12px 16px;border-radius:10px;background:rgba(255,255,255,0.02);border:1px solid rgba(255,255,255,0.05);font-size:13px;line-height:1.6;color:#a0aec0;animation:slideInLeft 0.4s ease both;}
|
| 99 |
+
.insight-item:hover{background:rgba(255,255,255,0.04);}
|
| 100 |
+
.insight-dot{flex-shrink:0;width:8px;height:8px;border-radius:50%;margin-top:6px;}
|
| 101 |
+
/* ββ Timeline bars ββ */
|
| 102 |
+
.bar-wrap{display:flex;flex-direction:column;align-items:center;gap:4px;flex:1;min-width:0;position:relative;}
|
| 103 |
+
.bar-outer{width:100%;background:rgba(255,255,255,0.05);border-radius:4px 4px 0 0;overflow:hidden;position:relative;}
|
| 104 |
+
.bar-inner{width:100%;border-radius:4px 4px 0 0;transition:height 0.8s cubic-bezier(0.22,1,0.36,1);}
|
| 105 |
+
.bar-wrap:hover .bar-tooltip{opacity:1;transform:translateY(-4px);}
|
| 106 |
+
.bar-tooltip{position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);background:rgba(10,10,20,0.95);border:1px solid rgba(255,255,255,0.1);border-radius:6px;padding:4px 8px;font-size:10px;white-space:nowrap;pointer-events:none;opacity:0;transition:all 0.2s ease;z-index:10;font-family:'JetBrains Mono',monospace;}
|
| 107 |
+
/* ββ Meta grid ββ */
|
| 108 |
+
.meta-row{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid rgba(255,255,255,0.05);}
|
| 109 |
+
.meta-row:last-child{border-bottom:none;}
|
| 110 |
+
/* ββ Error ββ */
|
| 111 |
+
#errorSection{border-color:rgba(255,51,85,0.3)!important;background:rgba(255,51,85,0.04)!important;}
|
| 112 |
+
/* ββ Stat pills ββ */
|
| 113 |
+
.stat-pill{display:inline-flex;align-items:center;gap:8px;padding:8px 18px;border-radius:99px;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);font-size:12px;font-weight:600;letter-spacing:0.05em;color:#a0aec0;}
|
| 114 |
+
.stat-pill .pip{width:6px;height:6px;border-radius:50%;background:var(--g);box-shadow:0 0 6px var(--g);}
|
| 115 |
+
/* ββ Section label ββ */
|
| 116 |
+
.sec-label{font-size:10px;font-weight:700;letter-spacing:0.2em;text-transform:uppercase;color:#00aaff;display:flex;align-items:center;gap:8px;margin-bottom:14px;}
|
| 117 |
+
.sec-label::before{content:'';display:inline-block;width:3px;height:14px;background:#00aaff;border-radius:2px;box-shadow:0 0 8px #00aaff;}
|
| 118 |
+
/* ββ Model badge ββ */
|
| 119 |
+
#modelBadge{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:99px;background:rgba(0,255,136,0.08);border:1px solid rgba(0,255,136,0.25);font-size:11px;font-weight:600;letter-spacing:0.1em;color:var(--g);}
|
| 120 |
+
</style>
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
<!-- Particle canvas + grid -->
|
| 124 |
+
<canvas id="particles"></canvas>
|
| 125 |
+
<div class="grid-bg"></div>
|
| 126 |
+
|
| 127 |
+
<!-- ββ HEADER ββ -->
|
| 128 |
+
<header>
|
| 129 |
+
<div style="max-width:1100px;margin:0 auto;padding:0 24px;height:64px;display:flex;align-items:center;justify-content:space-between;">
|
| 130 |
+
<div style="display:flex;align-items:center;gap:14px;">
|
| 131 |
+
<!-- Animated eye logo -->
|
| 132 |
+
<div class="eye-scan" style="width:36px;height:36px;display:flex;align-items:center;justify-content:center;">
|
| 133 |
+
<svg width="36" height="36" viewBox="0 0 36 36" fill="none">
|
| 134 |
+
<ellipse cx="18" cy="18" rx="14" ry="9" stroke="#00ff88" stroke-width="1.5" opacity="0.9"/>
|
| 135 |
+
<circle cx="18" cy="18" r="5" fill="#00ff88" opacity="0.9"/>
|
| 136 |
+
<circle cx="18" cy="18" r="2.5" fill="#050508"/>
|
| 137 |
+
<path d="M4 18 Q18 4 32 18" stroke="#00ff88" stroke-width="0.8" stroke-dasharray="4 3" opacity="0.4">
|
| 138 |
+
<animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="8s" repeatCount="indefinite"/>
|
| 139 |
+
</path>
|
| 140 |
</svg>
|
| 141 |
</div>
|
| 142 |
<div>
|
| 143 |
+
<div style="font-size:13px;font-weight:700;letter-spacing:0.18em;color:#fff;">DEEPFAKE AUTHENTICATOR</div>
|
| 144 |
+
<div style="font-size:9px;letter-spacing:0.25em;color:var(--muted);font-family:'JetBrains Mono',monospace;">AI-POWERED VIDEO FORENSICS</div>
|
| 145 |
</div>
|
| 146 |
</div>
|
| 147 |
+
<div id="modelBadge">
|
| 148 |
+
<div class="status-dot"></div>
|
| 149 |
+
<span>ViT ENSEMBLE</span>
|
| 150 |
+
</div>
|
| 151 |
</div>
|
| 152 |
</header>
|
| 153 |
|
| 154 |
+
<!-- ββ MAIN ββ -->
|
| 155 |
+
<div style="position:relative;z-index:1;max-width:860px;margin:0 auto;padding:48px 24px 80px;">
|
| 156 |
+
|
| 157 |
+
<!-- Hero -->
|
| 158 |
+
<div class="fade-up" style="text-align:center;margin-bottom:48px;animation-delay:0.1s;">
|
| 159 |
+
<h1 style="font-size:clamp(2rem,5vw,3.5rem);font-weight:700;line-height:1.1;margin-bottom:16px;background:linear-gradient(135deg,#fff 30%,var(--g));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;">Is This Video Real?</h1>
|
| 160 |
+
<p style="color:var(--muted);font-size:15px;max-width:480px;margin:0 auto 28px;line-height:1.7;">Advanced AI ensemble detects facial manipulation with 99%+ accuracy using dual Vision Transformer models.</p>
|
| 161 |
+
<div style="display:flex;flex-wrap:wrap;gap:10px;justify-content:center;">
|
| 162 |
+
<div class="stat-pill"><span class="pip"></span>2 ViT Models</div>
|
| 163 |
+
<div class="stat-pill"><span class="pip"></span>40 Frame Analysis</div>
|
| 164 |
+
<div class="stat-pill"><span class="pip"></span>< 15s Detection</div>
|
| 165 |
+
</div>
|
| 166 |
+
</div>
|
| 167 |
|
| 168 |
+
<!-- ββ UPLOAD SECTION ββ -->
|
| 169 |
+
<section id="uploadSection" class="glass fade-up" style="padding:32px;margin-bottom:24px;animation-delay:0.2s;">
|
| 170 |
<div id="dropZone">
|
| 171 |
+
<!-- Upload prompt -->
|
| 172 |
+
<div id="uploadPrompt" style="text-align:center;padding:40px 24px;">
|
| 173 |
+
<div style="position:relative;width:80px;height:80px;margin:0 auto 20px;">
|
| 174 |
+
<div style="position:absolute;inset:0;border-radius:50%;border:1px dashed rgba(0,255,136,0.3);" class="orbit"></div>
|
| 175 |
+
<div style="position:absolute;inset:8px;border-radius:50%;border:1px solid rgba(0,255,136,0.15);"></div>
|
| 176 |
+
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;">
|
| 177 |
+
<svg width="32" height="32" fill="none" stroke="#00ff88" stroke-width="1.5" viewBox="0 0 24 24" opacity="0.8">
|
| 178 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5"/>
|
| 179 |
+
</svg>
|
| 180 |
+
</div>
|
| 181 |
</div>
|
| 182 |
+
<h3 style="font-size:17px;font-weight:600;color:#fff;margin-bottom:8px;">Drop Video for Forensic Analysis</h3>
|
| 183 |
+
<p style="font-size:13px;color:var(--muted);">Drag & drop or click to browse</p>
|
| 184 |
+
<p style="font-size:11px;color:var(--muted);margin-top:12px;opacity:0.6;font-family:'JetBrains Mono',monospace;">MP4 Β· AVI Β· MOV Β· MKV Β· WebM β Max 100MB</p>
|
| 185 |
</div>
|
| 186 |
+
<!-- File chosen state -->
|
| 187 |
+
<div id="fileChosen" class="hidden" style="width:100%;padding:28px 32px;display:flex;align-items:center;gap:20px;">
|
| 188 |
+
<div style="width:56px;height:56px;border-radius:12px;background:rgba(0,255,136,0.1);border:1px solid rgba(0,255,136,0.3);display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 0 20px rgba(0,255,136,0.15);">
|
| 189 |
+
<svg width="28" height="28" fill="none" stroke="#00ff88" stroke-width="1.5" viewBox="0 0 24 24">
|
| 190 |
+
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z"/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
</svg>
|
| 192 |
</div>
|
| 193 |
<div style="flex:1;min-width:0;">
|
| 194 |
+
<p id="chosenName" style="font-size:14px;font-weight:600;color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"></p>
|
| 195 |
+
<p id="chosenSize" style="font-size:12px;color:var(--muted);margin-top:4px;font-family:'JetBrains Mono',monospace;"></p>
|
| 196 |
</div>
|
| 197 |
+
<button id="clearBtn" style="padding:8px;color:var(--muted);background:none;border:none;cursor:pointer;border-radius:8px;transition:all 0.2s;" onmouseover="this.style.color='#ff3355';this.style.background='rgba(255,51,85,0.1)'" onmouseout="this.style.color='var(--muted)';this.style.background='none'">
|
| 198 |
+
<svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
</button>
|
| 200 |
</div>
|
| 201 |
</div>
|
| 202 |
+
<input type="file" id="fileInput" accept="video/*" style="display:none;"/>
|
| 203 |
+
<div style="margin-top:20px;">
|
| 204 |
+
<button id="analyzeBtn" disabled>
|
| 205 |
+
<span id="analyzeBtnText">Analyze Video</span>
|
|
|
|
|
|
|
| 206 |
</button>
|
| 207 |
</div>
|
| 208 |
+
</section>
|
| 209 |
+
|
| 210 |
+
<!-- ββ LOADING SECTION ββ -->
|
| 211 |
+
<section id="loadingSection" class="hidden glass fade-up" style="padding:48px 32px;text-align:center;margin-bottom:24px;">
|
| 212 |
+
<!-- Radar -->
|
| 213 |
+
<div style="position:relative;width:140px;height:140px;margin:0 auto 36px;">
|
| 214 |
+
<div class="radar-ring" style="width:140px;height:140px;"></div>
|
| 215 |
+
<div class="radar-ring" style="width:100px;height:100px;"></div>
|
| 216 |
+
<div class="radar-ring" style="width:60px;height:60px;"></div>
|
| 217 |
+
<div class="radar-sweep" style="width:70px;top:50%;left:50%;transform-origin:left center;"></div>
|
| 218 |
+
<div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:12px;height:12px;border-radius:50%;background:var(--g);box-shadow:0 0 15px var(--g);"></div>
|
| 219 |
</div>
|
| 220 |
+
<!-- Status -->
|
| 221 |
+
<p id="loadingStatus" style="font-size:11px;font-weight:700;letter-spacing:0.2em;color:#00aaff;text-transform:uppercase;margin-bottom:20px;font-family:'JetBrains Mono',monospace;">Initializing sequence...</p>
|
| 222 |
+
<!-- Progress -->
|
| 223 |
+
<div style="max-width:400px;margin:0 auto 32px;">
|
| 224 |
+
<div class="prog-track">
|
| 225 |
+
<div id="progressBar" style="width:0%;" class="prog-fill"></div>
|
| 226 |
+
</div>
|
| 227 |
</div>
|
| 228 |
+
<!-- Agent cards -->
|
| 229 |
+
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:12px;max-width:500px;margin:0 auto;">
|
| 230 |
+
<div id="ag0" class="agent-card" style="display:flex;align-items:center;gap:10px;">
|
| 231 |
+
<div class="agent-dot"></div>
|
| 232 |
+
<div style="text-align:left;">
|
| 233 |
+
<div style="font-size:11px;font-weight:600;color:#fff;letter-spacing:0.05em;">Frame Extractor</div>
|
| 234 |
+
<div style="font-size:10px;color:var(--muted);font-family:'JetBrains Mono',monospace;">Sampling keyframes</div>
|
| 235 |
+
</div>
|
| 236 |
</div>
|
| 237 |
+
<div id="ag1" class="agent-card" style="display:flex;align-items:center;gap:10px;">
|
| 238 |
+
<div class="agent-dot"></div>
|
| 239 |
+
<div style="text-align:left;">
|
| 240 |
+
<div style="font-size:11px;font-weight:600;color:#fff;letter-spacing:0.05em;">Face Detector</div>
|
| 241 |
+
<div style="font-size:10px;color:var(--muted);font-family:'JetBrains Mono',monospace;">Isolating regions</div>
|
| 242 |
+
</div>
|
| 243 |
</div>
|
| 244 |
+
<div id="ag2" class="agent-card" style="display:flex;align-items:center;gap:10px;">
|
| 245 |
+
<div class="agent-dot"></div>
|
| 246 |
+
<div style="text-align:left;">
|
| 247 |
+
<div style="font-size:11px;font-weight:600;color:#fff;letter-spacing:0.05em;">ViT Ensemble</div>
|
| 248 |
+
<div style="font-size:10px;color:var(--muted);font-family:'JetBrains Mono',monospace;">Neural inference</div>
|
| 249 |
+
</div>
|
| 250 |
</div>
|
| 251 |
+
<div id="ag3" class="agent-card" style="display:flex;align-items:center;gap:10px;">
|
| 252 |
+
<div class="agent-dot"></div>
|
| 253 |
+
<div style="text-align:left;">
|
| 254 |
+
<div style="font-size:11px;font-weight:600;color:#fff;letter-spacing:0.05em;">Report Builder</div>
|
| 255 |
+
<div style="font-size:10px;color:var(--muted);font-family:'JetBrains Mono',monospace;">Compiling results</div>
|
| 256 |
+
</div>
|
| 257 |
</div>
|
| 258 |
</div>
|
| 259 |
+
</section>
|
| 260 |
|
| 261 |
+
<!-- ββ RESULT SECTION ββ -->
|
| 262 |
+
<section id="resultSection" class="hidden fade-up" style="display:flex;flex-direction:column;gap:20px;">
|
| 263 |
|
| 264 |
+
<!-- Verdict Card -->
|
| 265 |
+
<div id="verdictCard" class="glass" style="padding:40px;display:flex;flex-wrap:wrap;align-items:center;gap:36px;">
|
| 266 |
+
<!-- Badge + label -->
|
| 267 |
+
<div style="display:flex;flex-direction:column;align-items:center;flex-shrink:0;">
|
| 268 |
+
<div id="verdictBadge" class="verdict-badge" style="margin-bottom:14px;background:rgba(5,5,8,0.8);">
|
| 269 |
+
<span id="verdictEmoji" style="font-size:2.5rem;"></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
</div>
|
| 271 |
+
<div id="verdictLabel" style="font-size:28px;font-weight:700;letter-spacing:0.15em;text-transform:uppercase;"></div>
|
| 272 |
+
<div style="font-size:9px;color:var(--muted);letter-spacing:0.25em;margin-top:4px;font-family:'JetBrains Mono',monospace;">VERDICT</div>
|
| 273 |
+
</div>
|
| 274 |
+
<!-- Confidence + risk -->
|
| 275 |
+
<div style="flex:1;min-width:220px;">
|
| 276 |
+
<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:10px;">
|
| 277 |
+
<span style="font-size:10px;color:var(--muted);letter-spacing:0.15em;text-transform:uppercase;">Confidence Score</span>
|
| 278 |
+
<span id="confValue" style="font-size:36px;font-weight:700;font-family:'JetBrains Mono',monospace;"></span>
|
| 279 |
+
</div>
|
| 280 |
+
<div class="conf-track" style="margin-bottom:20px;">
|
| 281 |
+
<div id="confBar" class="conf-fill" style="width:0%;"></div>
|
| 282 |
+
</div>
|
| 283 |
+
<div class="glass-sm" style="padding:14px 18px;display:flex;align-items:center;justify-content:space-between;">
|
| 284 |
+
<span style="font-size:10px;color:var(--muted);letter-spacing:0.15em;text-transform:uppercase;">Risk Assessment</span>
|
| 285 |
+
<span id="riskNeedle"></span>
|
| 286 |
+
</div>
|
| 287 |
+
<div style="margin-top:12px;text-align:right;">
|
| 288 |
+
<span id="riskLabel" style="font-size:11px;color:var(--muted);font-family:'JetBrains Mono',monospace;"></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
</div>
|
| 290 |
</div>
|
| 291 |
</div>
|
| 292 |
|
| 293 |
<!-- Insights + Meta -->
|
| 294 |
+
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px;">
|
| 295 |
+
<div class="glass" style="padding:24px;">
|
| 296 |
+
<div class="sec-label">Analysis Insights</div>
|
| 297 |
+
<div id="detailsList" style="display:flex;flex-direction:column;gap:10px;"></div>
|
|
|
|
| 298 |
</div>
|
| 299 |
+
<div class="glass" style="padding:24px;display:flex;flex-direction:column;justify-content:space-between;">
|
| 300 |
+
<div>
|
| 301 |
+
<div class="sec-label">Video Metadata</div>
|
| 302 |
+
<div id="metaGrid"></div>
|
| 303 |
+
</div>
|
| 304 |
+
<div style="margin-top:16px;padding-top:14px;border-top:1px solid rgba(255,255,255,0.05);display:flex;align-items:center;gap:8px;">
|
| 305 |
+
<div style="width:6px;height:6px;border-radius:50%;background:var(--g);box-shadow:0 0 6px var(--g);"></div>
|
| 306 |
+
<span style="font-size:10px;color:var(--muted);letter-spacing:0.15em;text-transform:uppercase;font-family:'JetBrains Mono',monospace;">Models: ViT Ensemble</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
</div>
|
| 308 |
</div>
|
| 309 |
</div>
|
| 310 |
|
| 311 |
<!-- Frame Timeline -->
|
| 312 |
+
<div class="glass" style="padding:24px;">
|
| 313 |
+
<div class="sec-label">Frame Analysis Timeline</div>
|
| 314 |
+
<div id="timelineChart" style="display:flex;align-items:flex-end;gap:3px;height:80px;position:relative;padding-bottom:20px;"></div>
|
| 315 |
+
<div style="display:flex;justify-content:space-between;margin-top:8px;">
|
| 316 |
+
<span style="font-size:10px;color:var(--muted);font-family:'JetBrains Mono',monospace;">Frame 0</span>
|
| 317 |
+
<span style="font-size:10px;color:var(--muted);font-family:'JetBrains Mono',monospace;">Frame 40</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
</div>
|
|
|
|
| 319 |
</div>
|
| 320 |
|
| 321 |
+
<!-- Reset -->
|
| 322 |
+
<div style="text-align:center;margin-top:8px;">
|
| 323 |
+
<button onclick="resetAll()" style="padding:12px 28px;font-size:11px;font-weight:700;letter-spacing:0.15em;text-transform:uppercase;color:var(--muted);background:none;border:1px solid rgba(255,255,255,0.1);border-radius:10px;cursor:pointer;transition:all 0.3s;font-family:'Space Grotesk',sans-serif;" onmouseover="this.style.color='var(--g)';this.style.borderColor='rgba(0,255,136,0.4)';this.style.background='rgba(0,255,136,0.05)'" onmouseout="this.style.color='var(--muted)';this.style.borderColor='rgba(255,255,255,0.1)';this.style.background='none'">
|
| 324 |
+
β» Analyze Another Video
|
|
|
|
|
|
|
|
|
|
|
|
|
| 325 |
</button>
|
| 326 |
</div>
|
| 327 |
+
</section>
|
| 328 |
|
| 329 |
+
<!-- ββ ERROR SECTION ββ -->
|
| 330 |
+
<section id="errorSection" class="hidden glass fade-up" style="padding:28px 32px;margin-bottom:24px;">
|
| 331 |
+
<div style="display:flex;align-items:center;gap:12px;margin-bottom:10px;">
|
| 332 |
+
<svg width="22" height="22" fill="none" stroke="#ff3355" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/></svg>
|
| 333 |
+
<span style="font-size:12px;font-weight:700;letter-spacing:0.2em;color:#ff3355;text-transform:uppercase;font-family:'JetBrains Mono',monospace;">Analysis Failed</span>
|
|
|
|
| 334 |
</div>
|
| 335 |
+
<p id="errorMsg" style="font-size:13px;color:var(--muted);margin-left:34px;line-height:1.6;"></p>
|
| 336 |
+
<div style="margin-left:34px;margin-top:16px;">
|
| 337 |
+
<button onclick="resetAll()" style="font-size:11px;color:rgba(255,255,255,0.4);background:none;border:none;cursor:pointer;letter-spacing:0.15em;text-transform:uppercase;font-family:'Space Grotesk',sans-serif;transition:color 0.2s;" onmouseover="this.style.color='#fff'" onmouseout="this.style.color='rgba(255,255,255,0.4)'">β» Try Again</button>
|
| 338 |
+
</div>
|
| 339 |
+
</section>
|
|
|
|
|
|
|
|
|
|
| 340 |
|
| 341 |
+
</div><!-- /main -->
|
| 342 |
|
| 343 |
+
<footer style="position:relative;z-index:1;text-align:center;padding:24px;font-size:10px;color:rgba(90,106,122,0.5);letter-spacing:0.2em;text-transform:uppercase;font-family:'JetBrains Mono',monospace;">
|
| 344 |
+
Deepfake Authenticator Β· Secure Local Inference Β· ViT Ensemble v2
|
|
|
|
| 345 |
</footer>
|
| 346 |
|
| 347 |
+
<script>
|
| 348 |
+
// ββ Particle background ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 349 |
+
(function(){
|
| 350 |
+
const c=document.getElementById('particles');
|
| 351 |
+
const ctx=c.getContext('2d');
|
| 352 |
+
let W,H,pts=[];
|
| 353 |
+
function resize(){W=c.width=window.innerWidth;H=c.height=window.innerHeight;}
|
| 354 |
+
resize();window.addEventListener('resize',resize);
|
| 355 |
+
for(let i=0;i<60;i++)pts.push({x:Math.random()*W,y:Math.random()*H,vx:(Math.random()-0.5)*0.3,vy:(Math.random()-0.5)*0.3,r:Math.random()*1.5+0.5,a:Math.random()});
|
| 356 |
+
function draw(){
|
| 357 |
+
ctx.clearRect(0,0,W,H);
|
| 358 |
+
pts.forEach(p=>{
|
| 359 |
+
p.x+=p.vx;p.y+=p.vy;
|
| 360 |
+
if(p.x<0||p.x>W)p.vx*=-1;
|
| 361 |
+
if(p.y<0||p.y>H)p.vy*=-1;
|
| 362 |
+
ctx.beginPath();ctx.arc(p.x,p.y,p.r,0,Math.PI*2);
|
| 363 |
+
ctx.fillStyle=`rgba(0,255,136,${0.15+p.a*0.2})`;ctx.fill();
|
| 364 |
+
});
|
| 365 |
+
// draw connections
|
| 366 |
+
for(let i=0;i<pts.length;i++)for(let j=i+1;j<pts.length;j++){
|
| 367 |
+
const dx=pts[i].x-pts[j].x,dy=pts[i].y-pts[j].y,d=Math.sqrt(dx*dx+dy*dy);
|
| 368 |
+
if(d<120){ctx.beginPath();ctx.moveTo(pts[i].x,pts[i].y);ctx.lineTo(pts[j].x,pts[j].y);ctx.strokeStyle=`rgba(0,255,136,${0.06*(1-d/120)})`;ctx.lineWidth=0.5;ctx.stroke();}
|
| 369 |
+
}
|
| 370 |
+
requestAnimationFrame(draw);
|
| 371 |
}
|
| 372 |
+
draw();
|
| 373 |
+
})();
|
| 374 |
+
</script>
|
|
|
|
|
|
|
|
|
|
| 375 |
<script src="script.js"></script>
|
| 376 |
</body>
|
| 377 |
+
</html>
|
frontend/script.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
/**
|
| 2 |
-
* Deepfake Authenticator β Frontend Logic
|
| 3 |
*/
|
| 4 |
|
| 5 |
const API_BASE = (window.location.protocol === 'file:')
|
|
@@ -11,48 +11,38 @@ let selectedFile = null;
|
|
| 11 |
// ββ Boot ββββββββββββββββββββββββββββββββββββββ
|
| 12 |
window.addEventListener('load', () => {
|
| 13 |
initUpload();
|
| 14 |
-
pingHealth();
|
| 15 |
});
|
| 16 |
|
| 17 |
-
// ββ Health ββββββββββββββββββββββββββββββββββββ
|
| 18 |
-
async function pingHealth() {
|
| 19 |
-
const badge = document.getElementById('modelBadge');
|
| 20 |
-
for (let i = 0; i < 8; i++) {
|
| 21 |
-
try {
|
| 22 |
-
const r = await fetch(`${API_BASE}/health`);
|
| 23 |
-
if (r.ok) {
|
| 24 |
-
const d = await r.json();
|
| 25 |
-
if (d.ready) {
|
| 26 |
-
badge.textContent = d.model.toUpperCase();
|
| 27 |
-
badge.classList.add('ready');
|
| 28 |
-
return;
|
| 29 |
-
}
|
| 30 |
-
}
|
| 31 |
-
} catch (_) {}
|
| 32 |
-
badge.textContent = `CONNECTING ${i + 1}/8...`;
|
| 33 |
-
await sleep(2000);
|
| 34 |
-
}
|
| 35 |
-
badge.textContent = 'SERVER OFFLINE';
|
| 36 |
-
badge.style.borderColor = '#ff444444';
|
| 37 |
-
badge.style.color = '#ff4444aa';
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
// ββ Upload wiring βββββββββββββββββββββββββββββ
|
| 41 |
function initUpload() {
|
| 42 |
const zone = document.getElementById('dropZone');
|
| 43 |
const input = document.getElementById('fileInput');
|
| 44 |
const clear = document.getElementById('clearBtn');
|
|
|
|
| 45 |
|
| 46 |
zone.addEventListener('click', e => {
|
| 47 |
if (!e.target.closest('#clearBtn')) input.click();
|
| 48 |
});
|
|
|
|
| 49 |
input.addEventListener('change', () => {
|
| 50 |
if (input.files?.[0]) applyFile(input.files[0]);
|
| 51 |
});
|
| 52 |
-
clear.addEventListener('click', e => { e.stopPropagation(); clearFile(); });
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
zone.addEventListener('drop', e => {
|
| 57 |
e.preventDefault(); e.stopPropagation();
|
| 58 |
zone.classList.remove('drag-over');
|
|
@@ -60,6 +50,8 @@ function initUpload() {
|
|
| 60 |
if (f?.type.startsWith('video/')) applyFile(f);
|
| 61 |
else showError('Please drop a valid video file (MP4, AVI, MOV, MKV, WebM).');
|
| 62 |
});
|
|
|
|
|
|
|
| 63 |
}
|
| 64 |
|
| 65 |
function applyFile(file) {
|
|
@@ -67,10 +59,8 @@ function applyFile(file) {
|
|
| 67 |
document.getElementById('uploadPrompt').classList.add('hidden');
|
| 68 |
const fc = document.getElementById('fileChosen');
|
| 69 |
fc.classList.remove('hidden');
|
| 70 |
-
fc.style.display = 'flex';
|
| 71 |
document.getElementById('chosenName').textContent = file.name;
|
| 72 |
document.getElementById('chosenSize').textContent = fmtBytes(file.size);
|
| 73 |
-
|
| 74 |
const btn = document.getElementById('analyzeBtn');
|
| 75 |
btn.disabled = false;
|
| 76 |
btn.classList.add('active');
|
|
@@ -88,16 +78,17 @@ function clearFile() {
|
|
| 88 |
|
| 89 |
function resetAll() {
|
| 90 |
clearFile();
|
| 91 |
-
['loadingSection','resultSection','errorSection'].forEach(hide);
|
|
|
|
| 92 |
}
|
| 93 |
|
| 94 |
// ββ Analyze βββββββββββββββββββββββββββββββββββ
|
| 95 |
async function analyzeVideo() {
|
| 96 |
if (!selectedFile) return;
|
| 97 |
|
|
|
|
| 98 |
show('loadingSection');
|
| 99 |
-
['resultSection','errorSection'].forEach(hide);
|
| 100 |
-
document.getElementById('analyzeBtn').disabled = true;
|
| 101 |
|
| 102 |
startAgentAnim();
|
| 103 |
|
|
@@ -110,102 +101,139 @@ async function analyzeVideo() {
|
|
| 110 |
const e = await res.json().catch(() => ({}));
|
| 111 |
throw new Error(e.detail || `Server error ${res.status}`);
|
| 112 |
}
|
| 113 |
-
|
|
|
|
| 114 |
} catch (err) {
|
| 115 |
-
showError(err.message || '
|
| 116 |
} finally {
|
| 117 |
hide('loadingSection');
|
| 118 |
stopAgentAnim();
|
| 119 |
-
document.getElementById('analyzeBtn').disabled = false;
|
| 120 |
}
|
| 121 |
}
|
| 122 |
|
| 123 |
-
// ββ
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
{ id:'ag1', label:'Detecting faces...', prog:38 },
|
| 127 |
-
{ id:'ag2', label:'Running AI ensemble...', prog:78 },
|
| 128 |
-
{ id:'ag3', label:'Generating report...', prog:94 },
|
| 129 |
-
];
|
| 130 |
-
const _timers = [];
|
| 131 |
|
| 132 |
function startAgentAnim() {
|
| 133 |
-
const
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
}
|
| 145 |
|
| 146 |
function stopAgentAnim() {
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
c.querySelector('.a-status').textContent = 'Waiting...';
|
| 153 |
});
|
| 154 |
-
document.getElementById('progressBar').style.width = '0%';
|
| 155 |
}
|
| 156 |
|
| 157 |
-
// ββ Render
|
| 158 |
function renderResult(data) {
|
| 159 |
-
const
|
| 160 |
-
const pct
|
| 161 |
|
| 162 |
-
// Verdict card
|
| 163 |
const vc = document.getElementById('verdictCard');
|
| 164 |
-
vc.
|
|
|
|
|
|
|
|
|
|
| 165 |
|
| 166 |
// Badge
|
| 167 |
const badge = document.getElementById('verdictBadge');
|
| 168 |
-
badge.className = 'verdict-badge ' + (
|
| 169 |
-
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
// Label
|
| 172 |
const lbl = document.getElementById('verdictLabel');
|
| 173 |
-
lbl.textContent =
|
| 174 |
-
lbl.style.color =
|
| 175 |
-
lbl.style.textShadow =
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
const bar = document.getElementById('confBar');
|
| 181 |
-
bar.className = 'conf-fill ' + (
|
| 182 |
setTimeout(() => { bar.style.width = pct + '%'; }, 80);
|
| 183 |
|
| 184 |
// Risk needle
|
| 185 |
const needle = document.getElementById('riskNeedle');
|
| 186 |
const riskLbl = document.getElementById('riskLabel');
|
| 187 |
-
setTimeout(() => { needle.style.left = pct + '%'; }, 80);
|
| 188 |
if (pct < 35) {
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
riskLbl.textContent = '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
} else {
|
| 195 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
}
|
| 197 |
|
| 198 |
// Insights
|
| 199 |
const dl = document.getElementById('detailsList');
|
| 200 |
dl.innerHTML = '';
|
| 201 |
-
|
|
|
|
|
|
|
|
|
|
| 202 |
const div = document.createElement('div');
|
| 203 |
div.className = 'insight-item';
|
| 204 |
-
div.style.animationDelay = (i *
|
| 205 |
-
div.
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
<span>${esc(txt)}</span>`;
|
| 209 |
dl.appendChild(div);
|
| 210 |
});
|
| 211 |
|
|
@@ -213,89 +241,114 @@ function renderResult(data) {
|
|
| 213 |
const meta = data.metadata || {};
|
| 214 |
const mg = document.getElementById('metaGrid');
|
| 215 |
mg.innerHTML = '';
|
| 216 |
-
[
|
| 217 |
-
['Frames Analyzed',
|
| 218 |
-
['
|
| 219 |
-
['
|
| 220 |
-
['
|
| 221 |
-
['
|
| 222 |
-
|
| 223 |
-
|
| 224 |
const row = document.createElement('div');
|
| 225 |
row.className = 'meta-row';
|
| 226 |
-
row.innerHTML = `<span
|
| 227 |
mg.appendChild(row);
|
| 228 |
});
|
| 229 |
|
| 230 |
-
//
|
| 231 |
-
|
| 232 |
|
| 233 |
show('resultSection');
|
| 234 |
-
document.getElementById('resultSection').scrollIntoView({ behavior: 'smooth', block: 'start' });
|
| 235 |
}
|
| 236 |
|
| 237 |
-
|
| 238 |
-
function buildTimeline(frames) {
|
| 239 |
const chart = document.getElementById('timelineChart');
|
|
|
|
| 240 |
chart.innerHTML = '';
|
| 241 |
|
|
|
|
| 242 |
if (!frames.length) {
|
| 243 |
-
chart.innerHTML = '<
|
| 244 |
return;
|
| 245 |
}
|
| 246 |
|
| 247 |
-
const maxH =
|
| 248 |
-
const
|
|
|
|
| 249 |
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
setTimeout(() => {
|
| 276 |
});
|
| 277 |
-
}
|
| 278 |
|
| 279 |
-
//
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
document.
|
| 283 |
-
|
|
|
|
|
|
|
|
|
|
| 284 |
}
|
| 285 |
|
| 286 |
// ββ Helpers βββββββββββββββββββββββββββββββββββ
|
| 287 |
function show(id) {
|
| 288 |
const el = document.getElementById(id);
|
|
|
|
| 289 |
el.classList.remove('hidden');
|
| 290 |
-
el.style.display = '';
|
| 291 |
}
|
| 292 |
-
|
| 293 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
function fmtBytes(b) {
|
| 295 |
-
if (b < 1024)
|
| 296 |
-
if (b < 1048576) return (b/1024).toFixed(1) + ' KB';
|
| 297 |
-
return (b/1048576).toFixed(1) + ' MB';
|
| 298 |
}
|
|
|
|
| 299 |
function esc(s) {
|
| 300 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
}
|
|
|
|
| 1 |
/**
|
| 2 |
+
* Deepfake Authenticator β Frontend Logic (Cinematic Dark UI)
|
| 3 |
*/
|
| 4 |
|
| 5 |
const API_BASE = (window.location.protocol === 'file:')
|
|
|
|
| 11 |
// ββ Boot ββββββββββββββββββββββββββββββββββββββ
|
| 12 |
window.addEventListener('load', () => {
|
| 13 |
initUpload();
|
|
|
|
| 14 |
});
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
// ββ Upload wiring βββββββββββββββββββββββββββββ
|
| 17 |
function initUpload() {
|
| 18 |
const zone = document.getElementById('dropZone');
|
| 19 |
const input = document.getElementById('fileInput');
|
| 20 |
const clear = document.getElementById('clearBtn');
|
| 21 |
+
const btn = document.getElementById('analyzeBtn');
|
| 22 |
|
| 23 |
zone.addEventListener('click', e => {
|
| 24 |
if (!e.target.closest('#clearBtn')) input.click();
|
| 25 |
});
|
| 26 |
+
|
| 27 |
input.addEventListener('change', () => {
|
| 28 |
if (input.files?.[0]) applyFile(input.files[0]);
|
| 29 |
});
|
|
|
|
| 30 |
|
| 31 |
+
clear.addEventListener('click', e => {
|
| 32 |
+
e.stopPropagation();
|
| 33 |
+
clearFile();
|
| 34 |
+
});
|
| 35 |
+
|
| 36 |
+
zone.addEventListener('dragover', e => {
|
| 37 |
+
e.preventDefault(); e.stopPropagation();
|
| 38 |
+
zone.classList.add('drag-over');
|
| 39 |
+
});
|
| 40 |
+
|
| 41 |
+
zone.addEventListener('dragleave', e => {
|
| 42 |
+
e.preventDefault();
|
| 43 |
+
zone.classList.remove('drag-over');
|
| 44 |
+
});
|
| 45 |
+
|
| 46 |
zone.addEventListener('drop', e => {
|
| 47 |
e.preventDefault(); e.stopPropagation();
|
| 48 |
zone.classList.remove('drag-over');
|
|
|
|
| 50 |
if (f?.type.startsWith('video/')) applyFile(f);
|
| 51 |
else showError('Please drop a valid video file (MP4, AVI, MOV, MKV, WebM).');
|
| 52 |
});
|
| 53 |
+
|
| 54 |
+
btn.addEventListener('click', analyzeVideo);
|
| 55 |
}
|
| 56 |
|
| 57 |
function applyFile(file) {
|
|
|
|
| 59 |
document.getElementById('uploadPrompt').classList.add('hidden');
|
| 60 |
const fc = document.getElementById('fileChosen');
|
| 61 |
fc.classList.remove('hidden');
|
|
|
|
| 62 |
document.getElementById('chosenName').textContent = file.name;
|
| 63 |
document.getElementById('chosenSize').textContent = fmtBytes(file.size);
|
|
|
|
| 64 |
const btn = document.getElementById('analyzeBtn');
|
| 65 |
btn.disabled = false;
|
| 66 |
btn.classList.add('active');
|
|
|
|
| 78 |
|
| 79 |
function resetAll() {
|
| 80 |
clearFile();
|
| 81 |
+
['loadingSection', 'resultSection', 'errorSection'].forEach(hide);
|
| 82 |
+
show('uploadSection');
|
| 83 |
}
|
| 84 |
|
| 85 |
// ββ Analyze βββββββββββββββββββββββββββββββββββ
|
| 86 |
async function analyzeVideo() {
|
| 87 |
if (!selectedFile) return;
|
| 88 |
|
| 89 |
+
hide('uploadSection');
|
| 90 |
show('loadingSection');
|
| 91 |
+
['resultSection', 'errorSection'].forEach(hide);
|
|
|
|
| 92 |
|
| 93 |
startAgentAnim();
|
| 94 |
|
|
|
|
| 101 |
const e = await res.json().catch(() => ({}));
|
| 102 |
throw new Error(e.detail || `Server error ${res.status}`);
|
| 103 |
}
|
| 104 |
+
const data = await res.json();
|
| 105 |
+
renderResult(data);
|
| 106 |
} catch (err) {
|
| 107 |
+
showError(err.message || 'Connection to analysis engine failed.');
|
| 108 |
} finally {
|
| 109 |
hide('loadingSection');
|
| 110 |
stopAgentAnim();
|
|
|
|
| 111 |
}
|
| 112 |
}
|
| 113 |
|
| 114 |
+
// ββ Loading Animation βββββββββββββββββββββββββ
|
| 115 |
+
let _simTimer = null;
|
| 116 |
+
let _agentTimer = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
function startAgentAnim() {
|
| 119 |
+
const statusEl = document.getElementById('loadingStatus');
|
| 120 |
+
const progBar = document.getElementById('progressBar');
|
| 121 |
+
|
| 122 |
+
const phases = [
|
| 123 |
+
{ p: 12, msg: 'Extracting keyframes...', ag: 0 },
|
| 124 |
+
{ p: 35, msg: 'Isolating facial regions...', ag: 1 },
|
| 125 |
+
{ p: 65, msg: 'Running ViT neural inference...', ag: 2 },
|
| 126 |
+
{ p: 85, msg: 'Cross-referencing metadata...', ag: 2 },
|
| 127 |
+
{ p: 95, msg: 'Compiling authenticity report...', ag: 3 },
|
| 128 |
+
];
|
| 129 |
+
|
| 130 |
+
// Reset agents
|
| 131 |
+
[0,1,2,3].forEach(i => {
|
| 132 |
+
const card = document.getElementById('ag' + i);
|
| 133 |
+
if (card) card.classList.remove('active');
|
| 134 |
});
|
| 135 |
+
|
| 136 |
+
statusEl.textContent = 'Initializing sequence...';
|
| 137 |
+
progBar.style.width = '0%';
|
| 138 |
+
|
| 139 |
+
let idx = 0;
|
| 140 |
+
_simTimer = setInterval(() => {
|
| 141 |
+
if (idx < phases.length) {
|
| 142 |
+
const ph = phases[idx];
|
| 143 |
+
statusEl.textContent = ph.msg;
|
| 144 |
+
progBar.style.width = ph.p + '%';
|
| 145 |
+
const card = document.getElementById('ag' + ph.ag);
|
| 146 |
+
if (card) card.classList.add('active');
|
| 147 |
+
idx++;
|
| 148 |
+
}
|
| 149 |
+
}, 1100);
|
| 150 |
}
|
| 151 |
|
| 152 |
function stopAgentAnim() {
|
| 153 |
+
if (_simTimer) { clearInterval(_simTimer); _simTimer = null; }
|
| 154 |
+
document.getElementById('progressBar').style.width = '100%';
|
| 155 |
+
[0,1,2,3].forEach(i => {
|
| 156 |
+
const card = document.getElementById('ag' + i);
|
| 157 |
+
if (card) card.classList.add('active');
|
|
|
|
| 158 |
});
|
|
|
|
| 159 |
}
|
| 160 |
|
| 161 |
+
// ββ Render Result βββββββββββββββββββββββββββββ
|
| 162 |
function renderResult(data) {
|
| 163 |
+
const isFake = data.result === 'FAKE';
|
| 164 |
+
const pct = data.confidence;
|
| 165 |
|
| 166 |
+
// Verdict card border glow
|
| 167 |
const vc = document.getElementById('verdictCard');
|
| 168 |
+
vc.style.borderColor = isFake ? 'rgba(255,51,85,0.5)' : 'rgba(0,255,136,0.5)';
|
| 169 |
+
vc.style.boxShadow = isFake
|
| 170 |
+
? '0 0 50px rgba(255,51,85,0.15), inset 0 0 30px rgba(255,51,85,0.05)'
|
| 171 |
+
: '0 0 50px rgba(0,255,136,0.15), inset 0 0 30px rgba(0,255,136,0.05)';
|
| 172 |
|
| 173 |
// Badge
|
| 174 |
const badge = document.getElementById('verdictBadge');
|
| 175 |
+
badge.className = 'verdict-badge ' + (isFake ? 'fake' : 'real');
|
| 176 |
+
badge.style.background = isFake ? 'rgba(255,51,85,0.08)' : 'rgba(0,255,136,0.08)';
|
| 177 |
+
|
| 178 |
+
// Emoji
|
| 179 |
+
document.getElementById('verdictEmoji').textContent = isFake ? 'β ' : 'β';
|
| 180 |
|
| 181 |
// Label
|
| 182 |
const lbl = document.getElementById('verdictLabel');
|
| 183 |
+
lbl.textContent = isFake ? 'DEEPFAKE' : 'AUTHENTIC';
|
| 184 |
+
lbl.style.color = isFake ? '#ff3355' : '#00ff88';
|
| 185 |
+
lbl.style.textShadow = isFake
|
| 186 |
+
? '0 0 20px rgba(255,51,85,0.7)'
|
| 187 |
+
: '0 0 20px rgba(0,255,136,0.7)';
|
| 188 |
+
if (isFake) lbl.classList.add('glitch-text');
|
| 189 |
+
else lbl.classList.remove('glitch-text');
|
| 190 |
+
|
| 191 |
+
// Confidence value
|
| 192 |
+
const cv = document.getElementById('confValue');
|
| 193 |
+
cv.textContent = pct + '%';
|
| 194 |
+
cv.style.color = isFake ? '#ff3355' : '#00ff88';
|
| 195 |
+
|
| 196 |
+
// Confidence bar
|
| 197 |
const bar = document.getElementById('confBar');
|
| 198 |
+
bar.className = 'conf-fill ' + (isFake ? 'fake' : 'real');
|
| 199 |
setTimeout(() => { bar.style.width = pct + '%'; }, 80);
|
| 200 |
|
| 201 |
// Risk needle
|
| 202 |
const needle = document.getElementById('riskNeedle');
|
| 203 |
const riskLbl = document.getElementById('riskLabel');
|
|
|
|
| 204 |
if (pct < 35) {
|
| 205 |
+
needle.textContent = 'LOW RISK';
|
| 206 |
+
needle.style.color = '#00ff88';
|
| 207 |
+
needle.style.borderColor = 'rgba(0,255,136,0.35)';
|
| 208 |
+
needle.style.background = 'rgba(0,255,136,0.08)';
|
| 209 |
+
if (riskLbl) riskLbl.textContent = 'Minimal manipulation indicators detected';
|
| 210 |
+
} else if (pct < 65) {
|
| 211 |
+
needle.textContent = 'MEDIUM RISK';
|
| 212 |
+
needle.style.color = '#ffaa00';
|
| 213 |
+
needle.style.borderColor = 'rgba(255,170,0,0.35)';
|
| 214 |
+
needle.style.background = 'rgba(255,170,0,0.08)';
|
| 215 |
+
if (riskLbl) riskLbl.textContent = 'Moderate anomalies detected β review advised';
|
| 216 |
} else {
|
| 217 |
+
needle.textContent = 'CRITICAL RISK';
|
| 218 |
+
needle.style.color = '#ff3355';
|
| 219 |
+
needle.style.borderColor = 'rgba(255,51,85,0.35)';
|
| 220 |
+
needle.style.background = 'rgba(255,51,85,0.08)';
|
| 221 |
+
if (riskLbl) riskLbl.textContent = 'High-confidence manipulation signatures found';
|
| 222 |
}
|
| 223 |
|
| 224 |
// Insights
|
| 225 |
const dl = document.getElementById('detailsList');
|
| 226 |
dl.innerHTML = '';
|
| 227 |
+
const details = data.details || ['Analysis completed successfully.'];
|
| 228 |
+
const dotColor = isFake ? '#ff3355' : '#00ff88';
|
| 229 |
+
const dotGlow = isFake ? 'rgba(255,51,85,0.6)' : 'rgba(0,255,136,0.6)';
|
| 230 |
+
details.forEach((txt, i) => {
|
| 231 |
const div = document.createElement('div');
|
| 232 |
div.className = 'insight-item';
|
| 233 |
+
div.style.animationDelay = (i * 0.08) + 's';
|
| 234 |
+
div.style.borderLeftColor = dotColor;
|
| 235 |
+
div.style.borderLeft = `2px solid ${dotColor}`;
|
| 236 |
+
div.innerHTML = `<span class="insight-dot" style="background:${dotColor};box-shadow:0 0 8px ${dotGlow};"></span><span>${esc(txt)}</span>`;
|
|
|
|
| 237 |
dl.appendChild(div);
|
| 238 |
});
|
| 239 |
|
|
|
|
| 241 |
const meta = data.metadata || {};
|
| 242 |
const mg = document.getElementById('metaGrid');
|
| 243 |
mg.innerHTML = '';
|
| 244 |
+
const metaItems = [
|
| 245 |
+
['Frames Analyzed', meta.frames_analyzed ?? 'β'],
|
| 246 |
+
['Duration', meta.video_duration_sec ? meta.video_duration_sec + 's' : 'β'],
|
| 247 |
+
['FPS', meta.video_fps ?? 'β'],
|
| 248 |
+
['Resolution', meta.resolution ?? 'β'],
|
| 249 |
+
['Processing Time', data.processing_time_sec ? data.processing_time_sec + 's' : 'β'],
|
| 250 |
+
];
|
| 251 |
+
metaItems.forEach(([k, v]) => {
|
| 252 |
const row = document.createElement('div');
|
| 253 |
row.className = 'meta-row';
|
| 254 |
+
row.innerHTML = `<span style="font-size:11px;color:var(--muted);letter-spacing:0.08em;">${k}</span><span style="font-size:13px;font-weight:600;color:#fff;font-family:'JetBrains Mono',monospace;">${v}</span>`;
|
| 255 |
mg.appendChild(row);
|
| 256 |
});
|
| 257 |
|
| 258 |
+
// Frame timeline
|
| 259 |
+
renderTimeline(data, isFake);
|
| 260 |
|
| 261 |
show('resultSection');
|
|
|
|
| 262 |
}
|
| 263 |
|
| 264 |
+
function renderTimeline(data, isFake) {
|
|
|
|
| 265 |
const chart = document.getElementById('timelineChart');
|
| 266 |
+
if (!chart) return;
|
| 267 |
chart.innerHTML = '';
|
| 268 |
|
| 269 |
+
const frames = data.frame_scores || [];
|
| 270 |
if (!frames.length) {
|
| 271 |
+
chart.innerHTML = '<span style="font-size:11px;color:var(--muted);font-family:\'JetBrains Mono\',monospace;margin:auto;">No per-frame data available</span>';
|
| 272 |
return;
|
| 273 |
}
|
| 274 |
|
| 275 |
+
const maxH = 60; // px
|
| 276 |
+
const barColor = isFake ? '#ff3355' : '#00ff88';
|
| 277 |
+
const barGlow = isFake ? 'rgba(255,51,85,0.5)' : 'rgba(0,255,136,0.5)';
|
| 278 |
|
| 279 |
+
frames.forEach((score, i) => {
|
| 280 |
+
const pct = Math.round(score * 100);
|
| 281 |
+
const h = Math.max(4, Math.round((score) * maxH));
|
| 282 |
+
|
| 283 |
+
const wrap = document.createElement('div');
|
| 284 |
+
wrap.className = 'bar-wrap';
|
| 285 |
+
wrap.style.height = maxH + 'px';
|
| 286 |
+
|
| 287 |
+
const outer = document.createElement('div');
|
| 288 |
+
outer.className = 'bar-outer';
|
| 289 |
+
outer.style.height = maxH + 'px';
|
| 290 |
|
| 291 |
+
const inner = document.createElement('div');
|
| 292 |
+
inner.className = 'bar-inner';
|
| 293 |
+
inner.style.height = '0px';
|
| 294 |
+
inner.style.background = score > 0.5
|
| 295 |
+
? `linear-gradient(to top, ${barColor}, rgba(255,255,255,0.3))`
|
| 296 |
+
: 'rgba(255,255,255,0.12)';
|
| 297 |
+
if (score > 0.5) inner.style.boxShadow = `0 0 8px ${barGlow}`;
|
| 298 |
+
|
| 299 |
+
outer.appendChild(inner);
|
| 300 |
+
|
| 301 |
+
const tip = document.createElement('div');
|
| 302 |
+
tip.className = 'bar-tooltip';
|
| 303 |
+
tip.textContent = `F${i+1}: ${pct}%`;
|
| 304 |
+
|
| 305 |
+
wrap.appendChild(outer);
|
| 306 |
+
wrap.appendChild(tip);
|
| 307 |
+
chart.appendChild(wrap);
|
| 308 |
+
|
| 309 |
+
// Animate in
|
| 310 |
+
setTimeout(() => { inner.style.height = h + 'px'; }, 50 + i * 20);
|
| 311 |
});
|
|
|
|
| 312 |
|
| 313 |
+
// Threshold line at 50%
|
| 314 |
+
const line = document.createElement('div');
|
| 315 |
+
line.style.cssText = `position:absolute;left:0;right:0;bottom:${maxH*0.5}px;height:1px;background:rgba(255,170,0,0.4);pointer-events:none;`;
|
| 316 |
+
const lineLbl = document.createElement('span');
|
| 317 |
+
lineLbl.style.cssText = 'position:absolute;right:4px;top:-14px;font-size:9px;color:#ffaa00;font-family:\'JetBrains Mono\',monospace;letter-spacing:0.1em;';
|
| 318 |
+
lineLbl.textContent = '50%';
|
| 319 |
+
line.appendChild(lineLbl);
|
| 320 |
+
chart.appendChild(line);
|
| 321 |
}
|
| 322 |
|
| 323 |
// ββ Helpers βββββββββββββββββββββββββββββββββββ
|
| 324 |
function show(id) {
|
| 325 |
const el = document.getElementById(id);
|
| 326 |
+
if (!el) return;
|
| 327 |
el.classList.remove('hidden');
|
| 328 |
+
if (el.style.display === 'none') el.style.display = '';
|
| 329 |
}
|
| 330 |
+
|
| 331 |
+
function hide(id) {
|
| 332 |
+
const el = document.getElementById(id);
|
| 333 |
+
if (el) el.classList.add('hidden');
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
function fmtBytes(b) {
|
| 337 |
+
if (b < 1024) return b + ' B';
|
| 338 |
+
if (b < 1048576) return (b / 1024).toFixed(1) + ' KB';
|
| 339 |
+
return (b / 1048576).toFixed(1) + ' MB';
|
| 340 |
}
|
| 341 |
+
|
| 342 |
function esc(s) {
|
| 343 |
+
return String(s)
|
| 344 |
+
.replace(/&/g, '&')
|
| 345 |
+
.replace(/</g, '<')
|
| 346 |
+
.replace(/>/g, '>');
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
function showError(msg) {
|
| 350 |
+
hide('uploadSection');
|
| 351 |
+
hide('loadingSection');
|
| 352 |
+
document.getElementById('errorMsg').textContent = msg;
|
| 353 |
+
show('errorSection');
|
| 354 |
}
|