diff --git a/website/app.js b/website/app.js index 36b2921..bd47b58 100644 --- a/website/app.js +++ b/website/app.js @@ -29,8 +29,8 @@ document.addEventListener('DOMContentLoaded', () => { } }); }, { - rootMargin: '0px 0px -150px 0px', - threshold: 0.1 + rootMargin: '0px 0px -30px 0px', + threshold: 0.05 }); revealElements.forEach(el => revealObserver.observe(el)); @@ -433,7 +433,7 @@ document.addEventListener('DOMContentLoaded', () => { if (!launcher || !chip || !cursor || !playBtn || !pauseBtn) return; const EP_LEN = 2537; // fake 42:17 episode - const RATE = 8; // timelapse factor so the demo feels alive + const RATE = 1; // realtime: 1 wall-clock second = 1 video second const START_T = 754; // 12:34 const tabs = {}; @@ -548,14 +548,35 @@ document.addEventListener('DOMContentLoaded', () => { tabs[sourceKey].t = fraction * EP_LEN; renderTab(tabs[sourceKey]); showEvent('» ' + NAMES[sourceKey]); + // visible "cut" so the jump reads as a real seek, not a silent update + flashSeek(tabs[sourceKey].root); setTimeout(() => { tabs[peerKey].t = tabs[sourceKey].t; renderTab(tabs[peerKey]); + flashSeek(tabs[peerKey].root); pulse(); broadcasting = false; }, 90); }; + // Restart the film animations mid-stride + trigger the sweep overlay + let seekFlashTimers = []; + const flashSeek = (root) => { + if (!root) return; + root.classList.remove('demo-seeking'); + // Restart every animated layer from frame zero so the jump is visible + const film = root.querySelector('.demo-film'); + if (film) { + film.classList.add('demo-reset'); + void film.offsetWidth; // force reflow so the browser commits the reset + film.classList.remove('demo-reset'); + } + void root.offsetWidth; + root.classList.add('demo-seeking'); + const t = setTimeout(() => root.classList.remove('demo-seeking'), 360); + seekFlashTimers.push(t); + }; + const setPopupOpen = (open) => { scene.classList.toggle('popup-open', open); launcher.setAttribute('aria-expanded', open ? 'true' : 'false'); @@ -651,6 +672,10 @@ document.addEventListener('DOMContentLoaded', () => { const flashSelect = () => { if (!videoSelect) return; + // Actually pick the Stranger Things tab so the placeholder reads as chosen + if (videoSelect.options.length > 1) { + videoSelect.selectedIndex = 1; + } videoSelect.classList.remove('demo-attn'); void videoSelect.offsetWidth; videoSelect.classList.add('demo-attn'); diff --git a/website/locales/de.json b/website/locales/de.json index 54c82ff..fe042c3 100644 --- a/website/locales/de.json +++ b/website/locales/de.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Raum erstellen", "DEMO_JOINED": "Raum beigetreten", "DEMO_TAB_SELECTED": "Tab ausgewählt", + "DEMO_SELECT_PLACEHOLDER": "Video-Tab wählen…", "ADD_TO_CHROME": "Zu Chrome hinzufügen", "ADD_TO_FIREFOX": "Zu Firefox hinzufügen", "COMPAT_HEADING": "Funktioniert auf deinen Lieblingsplattformen", diff --git a/website/locales/en.json b/website/locales/en.json index 4134bbb..65e126f 100644 --- a/website/locales/en.json +++ b/website/locales/en.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Create Room", "DEMO_JOINED": "Room joined", "DEMO_TAB_SELECTED": "Tab selected", + "DEMO_SELECT_PLACEHOLDER": "Choose a video tab…", "ADD_TO_CHROME": "Add to Chrome", "ADD_TO_FIREFOX": "Add to Firefox", "COMPAT_HEADING": "Works on your favorite platforms", diff --git a/website/locales/es.json b/website/locales/es.json index 342cca6..239061e 100644 --- a/website/locales/es.json +++ b/website/locales/es.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Crear sala", "DEMO_JOINED": "Conectado a la sala", "DEMO_TAB_SELECTED": "Pestaña seleccionada", + "DEMO_SELECT_PLACEHOLDER": "Elige una pestaña de video…", "ADD_TO_CHROME": "Añadir a Chrome", "ADD_TO_FIREFOX": "Añadir a Firefox", "COMPAT_HEADING": "Funciona en tus plataformas favoritas", diff --git a/website/locales/fr.json b/website/locales/fr.json index 9a316d0..1e4b421 100644 --- a/website/locales/fr.json +++ b/website/locales/fr.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Créer un salon", "DEMO_JOINED": "Salon rejoint", "DEMO_TAB_SELECTED": "Onglet sélectionné", + "DEMO_SELECT_PLACEHOLDER": "Choisir un onglet vidéo…", "ADD_TO_CHROME": "Ajouter à Chrome", "ADD_TO_FIREFOX": "Ajouter à Firefox", "COMPAT_HEADING": "Fonctionne sur vos plateformes préférées", diff --git a/website/locales/it.json b/website/locales/it.json index ac8d658..02b820d 100644 --- a/website/locales/it.json +++ b/website/locales/it.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Crea stanza", "DEMO_JOINED": "Entrato nella stanza", "DEMO_TAB_SELECTED": "Scheda selezionata", + "DEMO_SELECT_PLACEHOLDER": "Scegli una scheda video…", "ADD_TO_CHROME": "Aggiungi a Chrome", "ADD_TO_FIREFOX": "Aggiungi a Firefox", "COMPAT_HEADING": "Compatibile con le tue piattaforme preferite", diff --git a/website/locales/ja.json b/website/locales/ja.json index 3ffd60d..e534edb 100644 --- a/website/locales/ja.json +++ b/website/locales/ja.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "ルームを作成", "DEMO_JOINED": "ルームに参加", "DEMO_TAB_SELECTED": "タブを選択済み", + "DEMO_SELECT_PLACEHOLDER": "動画タブを選ぶ…", "ADD_TO_CHROME": "Chromeに追加", "ADD_TO_FIREFOX": "Firefoxに追加", "COMPAT_HEADING": "お気に入りのプラットフォームで動作", diff --git a/website/locales/ko.json b/website/locales/ko.json index 662dd1b..12c123c 100644 --- a/website/locales/ko.json +++ b/website/locales/ko.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "방 만들기", "DEMO_JOINED": "방 참여됨", "DEMO_TAB_SELECTED": "탭 선택됨", + "DEMO_SELECT_PLACEHOLDER": "동영상 탭 선택…", "ADD_TO_CHROME": "Chrome에 추가", "ADD_TO_FIREFOX": "Firefox에 추가", "COMPAT_HEADING": "가장 좋아하는 플랫폼에서 작동합니다", diff --git a/website/locales/nl.json b/website/locales/nl.json index 7cbf669..8cc23f4 100644 --- a/website/locales/nl.json +++ b/website/locales/nl.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Kamer aanmaken", "DEMO_JOINED": "In de kamer", "DEMO_TAB_SELECTED": "Tabblad geselecteerd", + "DEMO_SELECT_PLACEHOLDER": "Kies een videotabblad…", "ADD_TO_CHROME": "Toevoegen aan Chrome", "ADD_TO_FIREFOX": "Toevoegen aan Firefox", "COMPAT_HEADING": "Werkt op uw favoriete platforms", diff --git a/website/locales/pl.json b/website/locales/pl.json index a43d46c..f651f19 100644 --- a/website/locales/pl.json +++ b/website/locales/pl.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Utwórz pokój", "DEMO_JOINED": "Dołączono do pokoju", "DEMO_TAB_SELECTED": "Karta wybrana", + "DEMO_SELECT_PLACEHOLDER": "Wybierz kartę wideo…", "ADD_TO_CHROME": "Dodaj do Chrome", "ADD_TO_FIREFOX": "Dodaj do Firefox", "COMPAT_HEADING": "Działa na Twoich ulubionych platformach", diff --git a/website/locales/pt-BR.json b/website/locales/pt-BR.json index 075c032..5b6c429 100644 --- a/website/locales/pt-BR.json +++ b/website/locales/pt-BR.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Criar sala", "DEMO_JOINED": "Entrou na sala", "DEMO_TAB_SELECTED": "Aba selecionada", + "DEMO_SELECT_PLACEHOLDER": "Escolha uma aba de vídeo…", "ADD_TO_CHROME": "Adicionar ao Chrome", "ADD_TO_FIREFOX": "Adicionar ao Firefox", "COMPAT_HEADING": "Funciona nas suas plataformas favoritas", diff --git a/website/locales/pt.json b/website/locales/pt.json index f3afdf7..e435a86 100644 --- a/website/locales/pt.json +++ b/website/locales/pt.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Criar sala", "DEMO_JOINED": "Entrou na sala", "DEMO_TAB_SELECTED": "Separador selecionado", + "DEMO_SELECT_PLACEHOLDER": "Escolha um separador de vídeo…", "ADD_TO_CHROME": "Adicionar ao Chrome", "ADD_TO_FIREFOX": "Adicionar ao Firefox", "COMPAT_HEADING": "Funciona nas suas plataformas favoritas", diff --git a/website/locales/ru.json b/website/locales/ru.json index 5bc8d70..70b1919 100644 --- a/website/locales/ru.json +++ b/website/locales/ru.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Создать комнату", "DEMO_JOINED": "В комнате", "DEMO_TAB_SELECTED": "Вкладка выбрана", + "DEMO_SELECT_PLACEHOLDER": "Выберите вкладку с видео…", "ADD_TO_CHROME": "Установить в Chrome", "ADD_TO_FIREFOX": "Установить в Firefox", "COMPAT_HEADING": "Работает на ваших любимых платформах", diff --git a/website/locales/tr.json b/website/locales/tr.json index 13ace76..7e2a5ca 100644 --- a/website/locales/tr.json +++ b/website/locales/tr.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Oda oluştur", "DEMO_JOINED": "Odaya katıldı", "DEMO_TAB_SELECTED": "Sekme seçildi", + "DEMO_SELECT_PLACEHOLDER": "Bir video sekmesi seçin…", "ADD_TO_CHROME": "Chrome'a Ekle", "ADD_TO_FIREFOX": "Firefox'a Ekle", "COMPAT_HEADING": "En sevdiğiniz platformlarda çalışır", diff --git a/website/locales/uk.json b/website/locales/uk.json index 2b39483..b5d50a1 100644 --- a/website/locales/uk.json +++ b/website/locales/uk.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "Створити кімнату", "DEMO_JOINED": "У кімнаті", "DEMO_TAB_SELECTED": "Вкладку вибрано", + "DEMO_SELECT_PLACEHOLDER": "Оберіть вкладку з відео…", "ADD_TO_CHROME": "Додати до Chrome", "ADD_TO_FIREFOX": "Додати до Firefox", "COMPAT_HEADING": "Працює на ваших улюблених платформах", diff --git a/website/locales/zh.json b/website/locales/zh.json index 21737a5..89f91b0 100644 --- a/website/locales/zh.json +++ b/website/locales/zh.json @@ -23,6 +23,7 @@ "DEMO_CREATE_ROOM": "创建房间", "DEMO_JOINED": "已加入房间", "DEMO_TAB_SELECTED": "已选择标签页", + "DEMO_SELECT_PLACEHOLDER": "选择视频标签页…", "ADD_TO_CHROME": "添加到Chrome", "ADD_TO_FIREFOX": "添加到Firefox", "COMPAT_HEADING": "适用于您最喜欢的平台", diff --git a/website/style.css b/website/style.css index 5f7fce9..22fa8c8 100644 --- a/website/style.css +++ b/website/style.css @@ -218,16 +218,16 @@ nav { .hero { min-height: 100vh; display: flex; - align-items: center; - padding-top: 8rem; - padding-bottom: 4rem; + align-items: flex-start; + padding-top: 7.5rem; + padding-bottom: 3rem; } .hero-grid { display: grid; grid-template-columns: 1.2fr 1fr; - align-items: center; - gap: 4rem; + align-items: start; + gap: 3rem; text-align: left; width: 100%; } @@ -236,7 +236,7 @@ nav { font-size: 4.5rem; font-weight: 800; line-height: 1.1; - margin-bottom: 1.5rem; + margin-bottom: 1.4rem; padding-bottom: 0.1em; background: linear-gradient(to bottom, #fff 40%, #6366f1); -webkit-background-clip: text; @@ -251,7 +251,7 @@ nav { .hero-text p, .hero-subtitle { font-size: 1.25rem; color: var(--text-muted); - margin-bottom: 2.5rem; + margin-bottom: 1.9rem; max-width: 600px; font-weight: 400; line-height: 1.6; @@ -343,6 +343,11 @@ nav { transition: transform 0.2s, box-shadow 0.2s, background 0.2s; } +.version-badge-below { + margin-bottom: 0; + margin-top: 1.5rem; +} + .version-badge:hover { background: rgba(99, 102, 241, 0.2); box-shadow: 0 0 16px rgba(99, 102, 241, 0.3); @@ -2977,13 +2982,13 @@ header[id] { .hero-demo-scene { position: relative; width: 100%; - height: 370px; - height: calc(63cqw + 84px); + height: 390px; + height: calc(66cqw + 78px); transition: height 0.45s cubic-bezier(0.22, 1, 0.36, 1); } .hero-demo-scene.popup-open { - height: 590px; + height: 600px; } /* While initializing, suppress all transitions so the popup can start closed @@ -3048,8 +3053,8 @@ header[id] { /* Video tab cards: a clean window cascade — the right one is in front */ .demo-tab-card { position: absolute; - width: 274px; - width: 62cqw; + width: 310px; + width: 70cqw; background: #131c31; border: 1px solid rgba(255, 255, 255, 0.09); border-radius: 14px; @@ -3068,8 +3073,8 @@ header[id] { /* Card A = the foreground window at the top right ("your" browser, hosts the extension icon in its toolbar) */ .demo-tab-a { - top: 30px; - right: 0; + top: 22px; + right: -3%; transform: rotate(1.2deg); transform-origin: top right; z-index: 3; @@ -3077,21 +3082,21 @@ header[id] { /* Card B = the friend's window, lower left, tucked behind */ .demo-tab-b { - top: 168px; - top: calc(28cqw + 44px); - left: 0; - transform: rotate(-1.5deg); + top: 142px; + top: calc(20cqw + 40px); + left: -3%; + transform: rotate(-1.6deg); transform-origin: top left; z-index: 2; } /* When the popup slides in from the right edge, the tabs step aside */ .hero-demo-scene.popup-open .demo-tab-a { - transform: rotate(1deg) translate(-55%, 2%) scale(0.9); + transform: rotate(1deg) translate(-48%, 2%) scale(0.88); } .hero-demo-scene.popup-open .demo-tab-b { - transform: rotate(-1.5deg) scale(0.95); + transform: rotate(-1.6deg) scale(0.94); } .demo-tab-titlebar { @@ -3533,62 +3538,134 @@ header[id] { height: 100%; } -.film-limb { - stroke: #e2e8f0; - stroke-width: 2; - stroke-linecap: round; +/* Cinematic "movie" scene: a moonlit landscape with parallax mountains, + twinkling stars, a glowing moon, and a drifting firefly. Every layer + freezes when playback pauses — on both tabs at once. */ +.demo-film { + position: absolute; + inset: 0; + width: 100%; + height: 100%; } -.film-walker { - transform: translate(-15px, 74px); - animation: filmWalk 10s linear infinite; -} - -@keyframes filmWalk { - to { transform: translate(175px, 74px); } -} - -.film-bob { - animation: filmBob 0.5s ease-in-out infinite alternate; -} - -@keyframes filmBob { - to { transform: translateY(-1.8px); } -} - -.film-swing-1, -.film-swing-2 { +/* Stars: staggered twinkle so the sky feels alive */ +.film-star { transform-box: fill-box; - transform-origin: top center; + transform-origin: center; + animation: filmTwinkle 2.8s ease-in-out infinite; +} +.film-star:nth-child(2) { animation-duration: 3.4s; animation-delay: 0.5s; } +.film-star:nth-child(3) { animation-duration: 2.4s; animation-delay: 1.1s; } +.film-star:nth-child(4) { animation-duration: 3.6s; animation-delay: 0.3s; } +.film-star:nth-child(5) { animation-duration: 2.6s; animation-delay: 1.6s; } +.film-star:nth-child(6) { animation-duration: 3.2s; animation-delay: 0.8s; } +.film-star:nth-child(7) { animation-duration: 2.2s; animation-delay: 1.3s; } + +@keyframes filmTwinkle { + 0%, 100% { opacity: 0.25; transform: scale(0.85); } + 50% { opacity: 1; transform: scale(1.15); } } -.film-swing-1 { animation: filmSwing 0.5s ease-in-out infinite alternate; } -.film-swing-2 { animation: filmSwing 0.5s ease-in-out infinite alternate-reverse; } - -@keyframes filmSwing { - from { transform: rotate(30deg); } - to { transform: rotate(-30deg); } +/* Moon: gentle glow pulse + slow arc drift */ +.film-moon { + transform-box: fill-box; + transform-origin: center; + animation: filmMoon 6s ease-in-out infinite alternate; } -.film-ball-x { - animation: filmBallX 6.5s linear infinite; +@keyframes filmMoon { + from { transform: translate(0, 0); filter: drop-shadow(0 0 4px rgba(241,245,249,0.5)); } + to { transform: translate(-6px, 3px); filter: drop-shadow(0 0 10px rgba(241,245,249,0.95)); } } -@keyframes filmBallX { - to { transform: translateX(175px); } +/* Mountain layers: subtle parallax sway (oscillates so it never runs off-edge) */ +.film-mtn-back { + transform-box: fill-box; + animation: filmMtnBack 24s ease-in-out infinite alternate; } -.film-ball { - animation: filmBallY 0.55s cubic-bezier(0.4, 0, 0.6, 1) infinite alternate; +@keyframes filmMtnBack { + from { transform: translateX(-3px); } + to { transform: translateX(3px); } } -@keyframes filmBallY { - to { transform: translateY(-16px); } +.film-mtn-front { + transform-box: fill-box; + animation: filmMtnFront 16s ease-in-out infinite alternate; +} + +@keyframes filmMtnFront { + from { transform: translateX(-5px); } + to { transform: translateX(5px); } +} + +/* Firefly: warm dot floating across the foreground */ +.film-firefly { + animation: filmFireflyX 11s linear infinite; +} + +@keyframes filmFireflyX { + from { transform: translate(15px, 0); } + to { transform: translate(145px, 0); } +} + +.film-firefly-light { + transform-box: fill-box; + transform-origin: center; + animation: filmFireflyBob 2.6s ease-in-out infinite alternate; + filter: drop-shadow(0 0 5px rgba(253, 224, 71, 0.95)); +} + +@keyframes filmFireflyBob { + from { transform: translateY(-4px) scale(0.9); opacity: 0.7; } + to { transform: translateY(4px) scale(1.15); opacity: 1; } } .demo-film * { animation-play-state: paused; } .demo-tab-card.playing .demo-film * { animation-play-state: running; } +/* Seek-reset: scrubbing restarts every film layer from frame zero so the + jump reads as a real cut, not a silent time update. */ +.demo-film.demo-reset * { + animation: none !important; +} + +/* Seek-break: scrubbing the timeline visibly glitches both videos so the + jump reads as a real cut instead of an invisible time update. A scanline + sweep + brightness pop, and the film animations restart mid-stride. */ +.demo-video-art { transition: filter 0.12s ease-out; } + +.demo-tab-card.demo-seeking .demo-video-art { + animation-play-state: paused; + filter: brightness(1.9) saturate(1.4) blur(0.6px); +} + +.demo-tab-card .demo-seek-sweep { + position: absolute; + inset: 0; + z-index: 4; + pointer-events: none; + opacity: 0; + background: linear-gradient(90deg, + transparent 0%, + rgba(129, 140, 248, 0.35) 20%, + rgba(255, 255, 255, 0.55) 50%, + rgba(129, 140, 248, 0.35) 80%, + transparent 100%); + mix-blend-mode: screen; + transform: translateX(-100%); +} + +.demo-tab-card.demo-seeking .demo-seek-sweep { + animation: demoSeekSweep 0.34s ease-out; +} + +@keyframes demoSeekSweep { + 0% { opacity: 0; transform: translateX(-100%); } + 20% { opacity: 1; } + 100% { opacity: 0; transform: translateX(100%); } +} + /* The sync chip only appears once the room is connected (story progression) */ .demo-sync-chip { opacity: 0; diff --git a/website/template.html b/website/template.html index 34ae4b7..66939f8 100644 --- a/website/template.html +++ b/website/template.html @@ -276,16 +276,12 @@
- - v2.2.1 OUT NOW - v2.2.1 JETZT VERFÜGBAR - -

{{HERO_TITLE}}

-

{{HERO_SUBTITLE}}

-
- +
- +