Загрузка кадров…
зажми и веди мышкой вправо →
SunSwing
Proof of concept — final design in development
  • 360° human-powered, no motor
  • 2 riders · ~7 m tall
  • Steel frame · 20+ yr life
  • from $9,000
Pre-order
SunSwing
Proof of concept — final design in development
YouTube
SunSwing в деле — 360° качеля на одного
SunSwing
Нравится
Поделиться
Сохранить
Pre-order SunSwing
Оставь заявку — свяжемся для деталей
Укажи email или телефон — хотя бы один способ связаться

Спасибо!

Заявка принята — свяжемся в ближайшее время.

Pre-order now!

SunSwing — hero scrub prototype

Зажми кнопку мыши и веди вправо — сцена перематывается покадрово, крупный план. В стартовой позиции (фас) доступны хотспоты: телефон (демо-видео) и блокнот (форма Pre-order) — просто наведи и кликни, без зажатия.

Что реализовано: покадровый скраббинг hero-сцены в обе стороны (WebP, два отдельных ролика — см. ниже) + клик-зум на телефон с запуском реального демо-видео качели + разворот блокнота с формой Pre-order + плавающая спек-карточка рядом с макетом + переключатель языка RU/EN/KA (кнопка в правом верхнем углу сцены) + фулскрин на весь браузер (letterbox 16:9, хотспоты остаются точными в % от «сцены») + кастомный курсор-ладошка (4 пальца, Disney-style): подрагивает при простое, сжимается в кулак при зажатии, показывает пальцем на телефон/блокнот.
Про переводы: грузинский — машинный перевод, не вычитан носителем, стоит проверить перед продакшеном (домен всё-таки .ge). Названия SunSwing и YouTube не переводятся нигде — бренды. Надпись "Pre-order now!" на обложке блокнота В САМОМ ВИДЕО (не в HTML-форме) не переводится в принципе — это часть сгенерированного ролика, впечатано в кадр, поменять можно только перегенерацией видео.
Про спек-карточку: показывается в том же окне видимости, что и хотспоты (только у рест-позиции) — макет сдвигается в кадре по ходу поворота, а карточка на фиксированных % от рамки, так что "рядом с макетом" она честно только в покое. Цифры взял из проектных данных (360°, 2 места, ~7м, сталь, 20+ лет, от $9,000) — поправь если что-то не то. Текст на английском, как и остальной контент в сцене (блокнот, YouTube-интерфейс) — скажи если нужно на русском. Слегка перекрывает висящие инструменты на фоне — это ок для плавающей карточки поверх фото, но подвинь если не нравится.
Важно (правая сторона): третья генерация. Вся композиция в кадре как на мастер-референсе (лампа, горшок, кружка, телефон, макет, блокнот — ничего не обрезано), старт в фас. Сырой ролик на 217-м кадре жёстко обрывается в другую, битую склейку (там же ломается телефон) — этот хвост просто отброшен, использованы только первые ~196 кадров. Известный косяк, оставлен осознанно: в кадре заметный наезд камеры (не лёгкое гуляние как раньше, а полноценный zoom-in по ходу поворота) — решили принять как есть, не тратить ещё одну попытку с Клингом. Кадры пересэмплированы по углу поворота камеры (не по времени) со сглаживанием — родная скорость облёта неравномерная (медленный старт), без сглаживания были бы рывки. Отдельно был баг с абсолютной позицией курсора при старте драга — пофикшено, отсчёт всегда от кадра на экране в момент нажатия.
Левая сторона добавлена задним числом: изначально влево крутить было некуда — все использованные генерации Клинга снимали облёт только в одну сторону. Ты попросил проверить историю генераций на предмет роликов с движением влево — прогнал через все 9 уникальных загруженных в этот чат видео (не только те 2-3, что реально обсуждались) оптический поток (та же техника, что и для сглаживания правой стороны), чтобы для каждого объективно определить направление камеры, а не гадать по превью. Нашлось одно: отдельная, нигде раньше не использованная генерация, которая (a) стартует с кадра, пиксель-в-пиксель совпадающего с мастер-референсом (значит это честное продолжение того же рест-кадра, а не другая сцена), и (b) крутит в обратную сторону, причём БЕЗ наезда камеры и без битых склеек — стабильнее правой стороны. Единственный минус — амплитуда движения в этом ролике примерно в 6-7 раз меньше правого (мало реального поворота), так что левый разворот заметно короче правого — это ограничение самой исходной съёмки, не что-то, что можно докрутить кодом. Кадры лежат отдельно в frames_left/ и пересэмплированы тем же методом (угол-равномерно + ограничение шага), что и правая сторона.
Про фулскрин: сцена теперь .hero = 100vw/100dvh на весь браузер, а собственно кадры/хотспоты живут внутри .stage — блока с точным 16:9 (letterbox: если окно шире/уже чем 16:9, по бокам или сверху/снизу чёрные поля, а не обрезка или искажение). Так хотспоты в % остаются точными на любом экране. Оверлеи видео и формы теперь растянуты на весь браузер (не только на сцену) — так эффектнее на полном экране.
Курсор — отказались от кастомного: была нарисованная от руки SVG-ладошка (3 состояния: открытая/кулак/указательный палец), с подрагиванием на старте. Смотрелась инородно рядом с обычным системным курсором на кнопках языков — два разных "языка" курсора на одной странице, плюс отдельно ловили баг с двоением. Убрали совсем. Теперь курсор везде системный: обычная стрелка над сценой, обычная "рука-указатель" при наведении на телефон/блокнот/кнопки — то же самое поведение, что уже было на переключателе языка, просто теперь одинаково по всей странице. Меньше кода, меньше багов, ожидаемо для пользователя.
Хотспоты пропадали при неточном возврате — теперь ещё и следят за объектом: раньше кнопки (плэй на телефоне, приордер на блокноте) показывались только в узком окне ±4 кадра от рест-позиции с фиксированной позицией в %, а сам макет в кадре по ходу поворота смещается — то есть даже в этом окне кружок мог быть чуть мимо телефона/блокнота. Сделал по-нормальному: прогнал оба видео через object tracking (OpenCV, покадрово отследил реальное положение телефона и блокнота в кадре), и теперь хотспоты (а) активны на всём диапазоне вращения в обе стороны, не только у покоя, и (б) физически едут по кадру вслед за объектом, а не висят на месте. Плюс осталась доводка до точного рест-кадра при отпускании близко к центру (справа порог ~22 кадра из 120, слева ~7 из 40 — короткий диапазон, иначе доводка съедала бы весь левый разворот) и обработка pointercancel/touchend/touchcancel на случай зависшего «зажато».
Рывок на стыке право/лево — почему он был и что сделал: это два независимых ролика от Клинга, оба стартуют «от фаса», но кадр 0 у левого ролика — не пиксель-в-пиксель тот же кадр, что у правого (замерил численно: разница ~15 пунктов на шкале diff, это не мелочь). Оба ролика честно продолжают один и тот же рест-кадр по смыслу, но генерация у Клинга стохастическая — идеального совпадения не бывает. Из-за этого при переходе через центр глаз ловил микро-скачок. Полностью убрать нельзя без перегенерации (а она всё равно не даст гарантии совпадения), поэтому сделал кросс-дисолв: первые 2 кадра левой стороны — не чистый ресемпл, а blend с мастер-кадром (с реальным весом, затухающим 0.45→0.75), так что скачок размазан на 2 кадра вместо одного жёсткого щелчка. Это смягчение, а не полное устранение — если приглядеться специально, зная куда смотреть, лёгкая нестыковка всё ещё считывается, но при обычном перетаскивании мышью уже не режет глаз.
Видео увеличено: карточка плеера была рассчитана на старый некрупный превью-блок (max-width 460px) и осталась мелкой после перехода на полноэкранный оверлей — подняли до 820px (~1.7x).
Блокнот теперь и правда похож на блокнот: подключил гугл-шрифт Caveat (рукописный, есть кириллица начиная с версии 1.500 — для русского ок; грузинского в нём нет, для KA само упадёт на системный шрифт, это нормально и не критично, учитывая что грузинский и так машинный перевод без вычитки). Страница формы теперь на разлинованной "бумаге" (горизонтальные линии + красная поля-линия слева, как в советской тетради), поля — не коробки, а просто линия на странице, текст в них тем же рукописным шрифтом, то есть по ощущению правда пишешь на листе, а не заполняешь веб-форму поверх картинки. При открытии блокнота заголовок и подзаголовок "дописываются" посимвольно с небольшим дрожанием (как будто их выводит рука), а поля формы проявляются по одному сверху вниз, а не все разом. Подписи полей (Имя/Email/...) оставил обычным мелким шрифтом — рукописным текстом делать интерфейсные подписи неудобно читать, а вот то, что реально "пишешь" — само поле — красиво в рукописном виде. Шрифт грузится с Google Fonts, то есть нужен обычный доступ в интернет у посетителя сайта (не VPN-специфика, просто как любой веб-шрифт) — если по какой-то причине не загрузится, браузер сам подставит обычный курсивный fallback, форма не сломается.
Форма шлёт в Google Sheets: нужно один раз задеплоить google-apps-script.gs (инструкция внутри файла) и вставить URL в GOOGLE_SCRIPT_URL в index.html. Без этого работает как mock ("Спасибо" без реальной отправки).
Плэй на телефоне и приордер на блокноте — убрал совсем: перепробовал несколько вариантов (чёрная плашка с текстом, жёлтый овал, свечение по наведению) и все либо смотрелись чужеродной кнопкой поверх фото, либо просто некрасиво (то самое пятно мочевого цвета). В итоге убрал визуальный элемент с обоих хотспотов полностью — ни кружка на телефоне, ни пятна на блокноте. Кликабельная область осталась та же (сам телефон / сама обложка блокнота), а единственная подсказка "тут можно нажать" — это системный курсор-рука при наведении, тот же, что и везде на странице. Текст "Pre-order" остался в DOM для скринридеров (visually-hidden), i18n не трогал.
Подсказка "тут можно крутить": первые две попытки нарисовать её сам (сначала две стрелочки по бокам от старого курсора, потом одна перерисованная иконка) по геометрии не совпадали с тем, что ты присылал — на третий раз просто вырезал иконку прямо из твоей картинки. Файл пришёл без реальной прозрачности (это был плоский скриншот с прозрачностью, отрисованной как обычная шахматная клетка — 15px квадраты), так что в лоб вставить нельзя было — программно вычислил точную сетку этой клетки, вычел её как фон и отдельно залил маленькие "дырки", которые получились внутри стрелки (там, где её собственная светлая заливка совпадала по цвету с клеткой). Файл — rotate-hint.png. Появляется по центру сцены на ~7 секунд после загрузки и гаснет либо сама по таймеру, либо сразу, как только человек реально начинает тянуть сцену мышью или пальцем.
Шрифт в полях формы: технически он и был Caveat (тот же, что в заголовке) — проверил через getComputedStyle, совпадает 1-в-1. Но по весу/размеру (600, 19px) он терялся рядом с жирным 30px заголовком и не читался как "тот же почерк". Поднял до 700/21px — тот же вес, что у заголовка, теперь видно, что это один шрифт, а не просто похожий.
Анимация открытия блокнота — сперва замедлил в 10 раз, потом обратно в 2 раза быстрее: было ~0.5 сек (глазом не успевал ничего разобрать) → поднял до 10x → оказалось слишком долго ждать реальную форму → срезал ровно в 2 раза. Сейчас флип обложки ~2.75с, наезд панели формы ~2.5с (плюс задержка 1.25с) — итого открывается примерно за ~3.5-4с, что примерно в 5 раз медленнее исходного. Дописывание заголовка от руки и появление полей формы по очереди подвинуты по времени вслед за этим, чтобы стартовать уже после того, как обложка реально открылась, а не наезжать друг на друга. Если и это долго/коротко — просто скажи на сколько, тут чисто вкусовая настройка, менять быстро.
Обложка блокнота в окне предзаказа — теперь настоящая: раньше это была нарисованная CSS-плашка (градиент + текст шрифтом Georgia) — грубая имитация. Вырезал реальный кадр обложки прямо из отснятого видео (рест-позиция, frames/f_001.webp), проапскейлил и подрезал резкость (кроп мелкий, 159×79px в исходнике, так что немного мягкий, но узнаваемый) — теперь при открытии блокнота видно ровно ту же обложку с той же надписью "Pre-order now!", что и на самом столе, а не перерисованную копию. Файл — book-cover.jpg. Текст на обложке остался только на английском (он впечатан в видео) — как и раньше в сцене, при смене языка на RU/KA он не переводится; текстовый span с переводом остался в DOM только для скринридеров.
Текст на обложке обрезался → contain+полоски → генерация со столом в кадре → финал: три захода подряд. 1) Кадр из видео был горизонтальный (~2:1), бокс под обложку в модалке — вертикальный (~0.68 w/h), cover обрезал почти всю ширину и текст улетал за край. 2) Временно поставил contain + подложку в тон дерева — текст переставал резаться, но появлялись полоски фона сверху/снизу. 3) Первая сгенерированная под нужные пропорции обложка технически подошла по соотношению сторон (0.667 к нужным 0.679), но в кадр вошёл кусок столешницы вокруг блокнота — при флипе было видно фото-в-фото (рамка стола + блокнот внутри неё), не просто обложка. Финал: перегенерировали с явным требованием "0% фона, обложка на 100% кадра" — теперь именно то, что нужно: только сама обложка, край в край, без стола и полей. 1024×1536, соотношение 0.667. background-size: cover без подложек — ни полосок, ни обрезки, ни лишнего стола. Файл — тот же book-cover.jpg, перезалит финальной версией.
Мобильная версия — была реально сломана, теперь работает: старый код держал .hero в 100vw/100dvh с флекс-центрированием и жёстко вписывал .stage в 16:9 — на портретном телефоне (например, 390×844) это давало сцену размером ~390×219px по центру огромного чёрного экрана: переключатель языка висел в воздухе, подсказка "тут можно тянуть" — в пустоте под полоской видео, а сама сцена — крошечная. В горизонтальной ориентации телефона было нормально (там форма экрана и так близка к 16:9), проблема была именно в портрете, а это то, как реально держат телефон. Фикс (@media max-width:760px): сцена больше не центрируется в 100dvh, а прижата к верху на всю ширину экрана — 16:9 остаётся неискажённым (важно: все % координаты хотспотов — PHONE_POS/NOTEBOOK_POS, снятые трекингом покадрово — считаны именно от честного 16:9, ничего не обрезано и не растянуто, так что телефон/блокнот кликаются в тех же местах, что и на десктопе). Под сценой освободившееся место — больше не пустой чёрный фон, а реальный контент: заголовок, те же цифры, что в плавающей spec-карточке на десктопе (spec-card на мобильных скрыт — не помещалась бы рядом с хотспотами), и кнопка "Pre-order", которая открывает ту же форму в блокноте (на тачскрине же нет ховера, чтобы найти кликабельную область на обложке — значит, нужна отдельная явная кнопка). Проверил на 390×844 и 375×667 (iPhone SE) — кнопка помещается без скролла на обоих. Десктоп и ландшафтный телефон не тронуты, там всё по-старому.