Spaces:
Sleeping
Sleeping
Ship gallery assets as LFS tar (fix broken images)
Browse files- static/index.html +154 -4
static/index.html
CHANGED
|
@@ -459,6 +459,101 @@
|
|
| 459 |
.lab-caption { font-size: 12px; color: var(--text-dim); margin: 0 0 10px; }
|
| 460 |
.lab-caption b { color: var(--accent); font-weight: 600; }
|
| 461 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
/* ---------- privacy modal ---------- */
|
| 463 |
#privacyModal {
|
| 464 |
position: fixed; inset: 0; z-index: 950;
|
|
@@ -502,6 +597,7 @@
|
|
| 502 |
<div class="brand">DEEP <span>ANALOG</span></div>
|
| 503 |
<a class="privacy-link" id="privacyOpen">Privacy</a>
|
| 504 |
</header>
|
|
|
|
| 505 |
<p class="tagline">
|
| 506 |
Upload a film scan you love — the model predicts a 3D LUT that captures its color character,
|
| 507 |
ready for Photoshop, Lightroom, DaVinci Resolve, or any editor.
|
|
@@ -549,7 +645,7 @@
|
|
| 549 |
|
| 550 |
<div class="action">
|
| 551 |
<button id="processBtn" disabled>Extract the look</button>
|
| 552 |
-
<div class="status" id="status"><div class="
|
| 553 |
</div>
|
| 554 |
|
| 555 |
<div id="results">
|
|
@@ -557,6 +653,8 @@
|
|
| 557 |
<div class="result-card" id="resultBody"></div>
|
| 558 |
</div>
|
| 559 |
|
|
|
|
|
|
|
| 560 |
<section class="demo" id="demoSection">
|
| 561 |
<h2>See it in action</h2>
|
| 562 |
<div class="demo-card">
|
|
@@ -586,6 +684,8 @@
|
|
| 586 |
</div>
|
| 587 |
</section>
|
| 588 |
|
|
|
|
|
|
|
| 589 |
<section class="demo" id="playSection">
|
| 590 |
<h2>Try it yourself — pick a pair</h2>
|
| 591 |
<p class="section-sub">Choose a reference look and an input photo, then run the pair through the model.
|
|
@@ -755,6 +855,9 @@
|
|
| 755 |
function fillZone(zoneId, file, clearFn) {
|
| 756 |
const zone = $(zoneId);
|
| 757 |
zone.classList.add('filled');
|
|
|
|
|
|
|
|
|
|
| 758 |
zone.querySelectorAll('img.preview, .file-chip').forEach(n => n.remove());
|
| 759 |
if (PREVIEWABLE.includes(file.type)) {
|
| 760 |
const img = document.createElement('img');
|
|
@@ -918,6 +1021,20 @@
|
|
| 918 |
cmp.addEventListener('pointerdown', e => { dragging = true; setPos(e.clientX); cmp.setPointerCapture(e.pointerId); });
|
| 919 |
cmp.addEventListener('pointermove', e => { if (dragging) setPos(e.clientX); });
|
| 920 |
cmp.addEventListener('pointerup', () => { dragging = false; });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 921 |
}
|
| 922 |
|
| 923 |
// ------------------------------------------------ look recipe (color mapping)
|
|
@@ -1489,8 +1606,9 @@
|
|
| 1489 |
$('instantWrap').style.display = 'block';
|
| 1490 |
$('liveHint').style.display = 'none';
|
| 1491 |
const cmp = $('labCompare');
|
| 1492 |
-
cmp.querySelector('.base-img')
|
| 1493 |
-
|
|
|
|
| 1494 |
cmp.querySelector('.top-img').src = input.src;
|
| 1495 |
}
|
| 1496 |
|
|
@@ -1542,10 +1660,12 @@
|
|
| 1542 |
});
|
| 1543 |
|
| 1544 |
// if a pre-render is ever missing, degrade gracefully to the live hint
|
| 1545 |
-
$('labCompare').querySelector('.base-img')
|
|
|
|
| 1546 |
$('instantWrap').style.display = 'none';
|
| 1547 |
$('liveHint').style.display = 'block';
|
| 1548 |
});
|
|
|
|
| 1549 |
|
| 1550 |
initCompare($('labCompare'));
|
| 1551 |
refresh();
|
|
@@ -1569,6 +1689,36 @@
|
|
| 1569 |
});
|
| 1570 |
})();
|
| 1571 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1572 |
// ------------------------------------------------ privacy modal
|
| 1573 |
['privacyOpen', 'privacyOpen2'].forEach(id => {
|
| 1574 |
const el = $(id);
|
|
|
|
| 459 |
.lab-caption { font-size: 12px; color: var(--text-dim); margin: 0 0 10px; }
|
| 460 |
.lab-caption b { color: var(--accent); font-weight: 600; }
|
| 461 |
|
| 462 |
+
/* ---------- motion & ambience ---------- */
|
| 463 |
+
body::after {
|
| 464 |
+
content: ""; position: fixed; inset: -20%;
|
| 465 |
+
pointer-events: none; z-index: 0;
|
| 466 |
+
background:
|
| 467 |
+
radial-gradient(640px 420px at 18% 24%, rgba(232,163,61,.055), transparent 62%),
|
| 468 |
+
radial-gradient(760px 520px at 82% 74%, rgba(90,125,165,.05), transparent 62%);
|
| 469 |
+
animation: drift 42s ease-in-out infinite alternate;
|
| 470 |
+
}
|
| 471 |
+
@keyframes drift { to { transform: translate(4%, -3%) scale(1.07); } }
|
| 472 |
+
.wrap { position: relative; z-index: 1; }
|
| 473 |
+
|
| 474 |
+
#cursorGlow {
|
| 475 |
+
position: fixed; width: 360px; height: 360px; border-radius: 50%;
|
| 476 |
+
pointer-events: none; z-index: 2;
|
| 477 |
+
background: radial-gradient(circle, rgba(232,163,61,.065), transparent 65%);
|
| 478 |
+
transform: translate(-50%, -50%);
|
| 479 |
+
mix-blend-mode: screen;
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
@keyframes fadeUp { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
|
| 483 |
+
.hero-title {
|
| 484 |
+
font-size: clamp(30px, 4.6vw, 46px); font-weight: 700;
|
| 485 |
+
letter-spacing: -0.015em; line-height: 1.1;
|
| 486 |
+
margin: 30px 0 12px;
|
| 487 |
+
animation: fadeUp .8s cubic-bezier(.2,.7,.2,1) both;
|
| 488 |
+
}
|
| 489 |
+
.hero-title em {
|
| 490 |
+
font-style: italic; color: var(--accent);
|
| 491 |
+
text-shadow: 0 0 26px rgba(232,163,61,.4);
|
| 492 |
+
}
|
| 493 |
+
.tagline { animation: fadeUp .8s .12s cubic-bezier(.2,.7,.2,1) both; }
|
| 494 |
+
.zones { animation: fadeUp .8s .22s cubic-bezier(.2,.7,.2,1) both; }
|
| 495 |
+
.brand { animation: flicker 1.5s steps(1) both; }
|
| 496 |
+
@keyframes flicker {
|
| 497 |
+
0% { opacity: 0; } 7% { opacity: 1; } 11% { opacity: .3; } 15% { opacity: 1; }
|
| 498 |
+
22% { opacity: .45; } 28% { opacity: 1; } 100% { opacity: 1; }
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
.reveal { opacity: 0; transform: translateY(24px);
|
| 502 |
+
transition: opacity .7s ease, transform .7s cubic-bezier(.2,.7,.2,1); }
|
| 503 |
+
.reveal.visible { opacity: 1; transform: none; }
|
| 504 |
+
|
| 505 |
+
.demo > h2 { display: flex; align-items: center; gap: 10px; }
|
| 506 |
+
.demo > h2::before { content: ""; width: 20px; height: 2px; background: var(--accent); flex: 0 0 auto; }
|
| 507 |
+
|
| 508 |
+
.filmstrip {
|
| 509 |
+
height: 26px; margin-top: 68px; border-radius: 5px;
|
| 510 |
+
background: #0f0f13; position: relative; opacity: .85;
|
| 511 |
+
}
|
| 512 |
+
.filmstrip::before, .filmstrip::after {
|
| 513 |
+
content: ""; position: absolute; left: 10px; right: 10px; height: 6px;
|
| 514 |
+
background: repeating-linear-gradient(90deg, #24242b 0 13px, transparent 13px 28px);
|
| 515 |
+
border-radius: 2px;
|
| 516 |
+
}
|
| 517 |
+
.filmstrip::before { top: 4px; }
|
| 518 |
+
.filmstrip::after { bottom: 4px; }
|
| 519 |
+
|
| 520 |
+
#processBtn:hover:not(:disabled) { box-shadow: 0 4px 26px rgba(232,163,61,.38); }
|
| 521 |
+
.try-btn:hover { box-shadow: 0 4px 20px rgba(232,163,61,.3); }
|
| 522 |
+
.dl-btn:hover { box-shadow: 0 3px 16px rgba(232,163,61,.14); transform: translateY(-1px); }
|
| 523 |
+
.dl-btn { transition: border-color .2s, transform .12s, box-shadow .2s; }
|
| 524 |
+
|
| 525 |
+
.zone.drag { transform: scale(1.015);
|
| 526 |
+
box-shadow: 0 0 0 4px var(--accent-soft), 0 10px 34px rgba(232,163,61,.16); }
|
| 527 |
+
.zone.pop { animation: pop .4s cubic-bezier(.2,.9,.3,1.35); }
|
| 528 |
+
@keyframes pop { 0% { transform: scale(.982); } 55% { transform: scale(1.012); } 100% { transform: scale(1); } }
|
| 529 |
+
|
| 530 |
+
.compare .divider { box-shadow: 0 0 16px rgba(232,163,61,.55); }
|
| 531 |
+
.compare .base-img { transition: opacity .35s; }
|
| 532 |
+
#results .result-card { animation: fadeUp .55s cubic-bezier(.2,.7,.2,1) both; }
|
| 533 |
+
.gate-card { animation: gateIn .8s cubic-bezier(.2,.7,.2,1) both; }
|
| 534 |
+
@keyframes gateIn { from { opacity: 0; transform: translateY(16px) scale(.975); } }
|
| 535 |
+
|
| 536 |
+
.filmloader { display: none; gap: 3px; }
|
| 537 |
+
.status.busy .filmloader { display: flex; }
|
| 538 |
+
.filmloader span {
|
| 539 |
+
width: 12px; height: 17px; border-radius: 2.5px;
|
| 540 |
+
background: var(--bg-3); border: 1px solid var(--line);
|
| 541 |
+
animation: frameblink 1.05s infinite;
|
| 542 |
+
}
|
| 543 |
+
.filmloader span:nth-child(2) { animation-delay: .15s; }
|
| 544 |
+
.filmloader span:nth-child(3) { animation-delay: .3s; }
|
| 545 |
+
.filmloader span:nth-child(4) { animation-delay: .45s; }
|
| 546 |
+
.filmloader span:nth-child(5) { animation-delay: .6s; }
|
| 547 |
+
@keyframes frameblink {
|
| 548 |
+
0%, 55%, 100% { background: var(--bg-3); border-color: var(--line); }
|
| 549 |
+
25% { background: var(--accent); border-color: var(--accent); }
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
@media (prefers-reduced-motion: reduce) {
|
| 553 |
+
*, *::before, *::after { animation: none !important; transition: none !important; }
|
| 554 |
+
.reveal { opacity: 1; transform: none; }
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
/* ---------- privacy modal ---------- */
|
| 558 |
#privacyModal {
|
| 559 |
position: fixed; inset: 0; z-index: 950;
|
|
|
|
| 597 |
<div class="brand">DEEP <span>ANALOG</span></div>
|
| 598 |
<a class="privacy-link" id="privacyOpen">Privacy</a>
|
| 599 |
</header>
|
| 600 |
+
<h1 class="hero-title">Steal the color of <em>any film</em>.</h1>
|
| 601 |
<p class="tagline">
|
| 602 |
Upload a film scan you love — the model predicts a 3D LUT that captures its color character,
|
| 603 |
ready for Photoshop, Lightroom, DaVinci Resolve, or any editor.
|
|
|
|
| 645 |
|
| 646 |
<div class="action">
|
| 647 |
<button id="processBtn" disabled>Extract the look</button>
|
| 648 |
+
<div class="status" id="status"><div class="filmloader" aria-hidden="true"><span></span><span></span><span></span><span></span><span></span></div><span id="statusText"></span></div>
|
| 649 |
</div>
|
| 650 |
|
| 651 |
<div id="results">
|
|
|
|
| 653 |
<div class="result-card" id="resultBody"></div>
|
| 654 |
</div>
|
| 655 |
|
| 656 |
+
<div class="filmstrip" aria-hidden="true"></div>
|
| 657 |
+
|
| 658 |
<section class="demo" id="demoSection">
|
| 659 |
<h2>See it in action</h2>
|
| 660 |
<div class="demo-card">
|
|
|
|
| 684 |
</div>
|
| 685 |
</section>
|
| 686 |
|
| 687 |
+
<div class="filmstrip" aria-hidden="true"></div>
|
| 688 |
+
|
| 689 |
<section class="demo" id="playSection">
|
| 690 |
<h2>Try it yourself — pick a pair</h2>
|
| 691 |
<p class="section-sub">Choose a reference look and an input photo, then run the pair through the model.
|
|
|
|
| 855 |
function fillZone(zoneId, file, clearFn) {
|
| 856 |
const zone = $(zoneId);
|
| 857 |
zone.classList.add('filled');
|
| 858 |
+
zone.classList.remove('pop');
|
| 859 |
+
void zone.offsetWidth; // restart the pop animation
|
| 860 |
+
zone.classList.add('pop');
|
| 861 |
zone.querySelectorAll('img.preview, .file-chip').forEach(n => n.remove());
|
| 862 |
if (PREVIEWABLE.includes(file.type)) {
|
| 863 |
const img = document.createElement('img');
|
|
|
|
| 1021 |
cmp.addEventListener('pointerdown', e => { dragging = true; setPos(e.clientX); cmp.setPointerCapture(e.pointerId); });
|
| 1022 |
cmp.addEventListener('pointermove', e => { if (dragging) setPos(e.clientX); });
|
| 1023 |
cmp.addEventListener('pointerup', () => { dragging = false; });
|
| 1024 |
+
|
| 1025 |
+
// cinematic sweep-in: divider glides from the right edge to center once
|
| 1026 |
+
let userTouched = false;
|
| 1027 |
+
cmp.addEventListener('pointerdown', () => { userTouched = true; }, { once: true });
|
| 1028 |
+
const t0 = performance.now();
|
| 1029 |
+
(function sweep(t) {
|
| 1030 |
+
if (userTouched) return;
|
| 1031 |
+
const p = Math.min((t - t0) / 950, 1);
|
| 1032 |
+
const e = 1 - Math.pow(1 - p, 3);
|
| 1033 |
+
const pos = 0.92 - 0.42 * e;
|
| 1034 |
+
divider.style.left = (pos * 100) + '%';
|
| 1035 |
+
top.style.clipPath = 'inset(0 0 0 ' + (pos * 100) + '%)';
|
| 1036 |
+
if (p < 1) requestAnimationFrame(sweep);
|
| 1037 |
+
})(t0);
|
| 1038 |
}
|
| 1039 |
|
| 1040 |
// ------------------------------------------------ look recipe (color mapping)
|
|
|
|
| 1606 |
$('instantWrap').style.display = 'block';
|
| 1607 |
$('liveHint').style.display = 'none';
|
| 1608 |
const cmp = $('labCompare');
|
| 1609 |
+
const base = cmp.querySelector('.base-img');
|
| 1610 |
+
base.style.opacity = '.25'; // crossfade while the new render loads
|
| 1611 |
+
base.src = 'static/lab/' + input.id + '_' + refId() + '.jpg';
|
| 1612 |
cmp.querySelector('.top-img').src = input.src;
|
| 1613 |
}
|
| 1614 |
|
|
|
|
| 1660 |
});
|
| 1661 |
|
| 1662 |
// if a pre-render is ever missing, degrade gracefully to the live hint
|
| 1663 |
+
const baseImg = $('labCompare').querySelector('.base-img');
|
| 1664 |
+
baseImg.addEventListener('error', () => {
|
| 1665 |
$('instantWrap').style.display = 'none';
|
| 1666 |
$('liveHint').style.display = 'block';
|
| 1667 |
});
|
| 1668 |
+
baseImg.addEventListener('load', () => { baseImg.style.opacity = '1'; });
|
| 1669 |
|
| 1670 |
initCompare($('labCompare'));
|
| 1671 |
refresh();
|
|
|
|
| 1689 |
});
|
| 1690 |
})();
|
| 1691 |
|
| 1692 |
+
// ------------------------------------------------ ambience
|
| 1693 |
+
// Scroll-reveal for below-the-fold sections
|
| 1694 |
+
document.querySelectorAll('section.demo, .filmstrip, footer').forEach(el =>
|
| 1695 |
+
el.classList.add('reveal'));
|
| 1696 |
+
const ro = new IntersectionObserver(entries => entries.forEach(e => {
|
| 1697 |
+
if (e.isIntersecting) { e.target.classList.add('visible'); ro.unobserve(e.target); }
|
| 1698 |
+
}), { threshold: 0.07 });
|
| 1699 |
+
document.querySelectorAll('.reveal').forEach(el => ro.observe(el));
|
| 1700 |
+
|
| 1701 |
+
// Cursor halation glow (desktop pointers only)
|
| 1702 |
+
if (window.matchMedia('(pointer:fine)').matches) {
|
| 1703 |
+
const glow = document.createElement('div');
|
| 1704 |
+
glow.id = 'cursorGlow';
|
| 1705 |
+
glow.style.opacity = '0';
|
| 1706 |
+
document.body.appendChild(glow);
|
| 1707 |
+
let gx = 0, gy = 0, pending = false;
|
| 1708 |
+
window.addEventListener('pointermove', e => {
|
| 1709 |
+
gx = e.clientX; gy = e.clientY;
|
| 1710 |
+
glow.style.opacity = '1';
|
| 1711 |
+
if (!pending) {
|
| 1712 |
+
pending = true;
|
| 1713 |
+
requestAnimationFrame(() => {
|
| 1714 |
+
glow.style.left = gx + 'px';
|
| 1715 |
+
glow.style.top = gy + 'px';
|
| 1716 |
+
pending = false;
|
| 1717 |
+
});
|
| 1718 |
+
}
|
| 1719 |
+
}, { passive: true });
|
| 1720 |
+
}
|
| 1721 |
+
|
| 1722 |
// ------------------------------------------------ privacy modal
|
| 1723 |
['privacyOpen', 'privacyOpen2'].forEach(id => {
|
| 1724 |
const el = $(id);
|