EtonMu commited on
Commit
cb5a6e0
·
verified ·
1 Parent(s): f42de0e

Ship gallery assets as LFS tar (fix broken images)

Browse files
Files changed (1) hide show
  1. 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&nbsp;LUT that captures its color character,
507
  ready for Photoshop, Lightroom, DaVinci&nbsp;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="spinner"></div><span id="statusText"></span></div>
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').src =
1493
- 'static/lab/' + input.id + '_' + refId() + '.jpg';
 
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').addEventListener('error', () => {
 
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&nbsp;LUT that captures its color character,
603
  ready for Photoshop, Lightroom, DaVinci&nbsp;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);