TGViewer
Channel Public Channel
Павел Мажуга | Frontend Developer

Павел Мажуга | Frontend Developer

@mazhugagl

Creative frontend developer. Рассказываю про креативные штуки в вебе, преимущественно WebGL/WebGPU. Делюсь демками анимаций, пишу статьи и просто мысли.

Открыт к сотрудничеству. Портфолио: https://pavelmazhuga.com

Личный аккаунт @pavelmazhuga
Subscribers
373
Photos
36
Videos
64
Links
82
Recent Posts 17 shown
Post #155 132
Как в TypeScript типизировать внешние данные (fetch JSON, куки, localStorage и т.п.)

Любой внешний payload на входе, например фетч или импорт JSON, по молчанию имеет тип any. Что мы обычно делаем? Правильно, кастим тип:


type PageResponse = {
status: "success" | "error";
data?: { contentHtml?: string; nextPageUrl?: string };
};

const json = (await response.json()) as PageResponse;


Но кастить тип через as равно врать компилятору.

TypeScript мы заткнули, только рантайм про контракт ничего не знает. Если формат поменялся, создается потенциальный баг в приложении.

Чтобы не врать, контракт нужно описать один раз и прогнать через него данные на границе. Для этого можно использовать Zod: схема валидирует в рантайме и сужает тип. Это называют "type narrowing через runtime parser": unknown/any -> parse -> конкретный тип.


const pageDataSchema = z.object({
contentHtml: z.string().optional(),
nextPageUrl: z.string().optional(),
});

const parsePageResponse = (raw: unknown) =>
z
.object({
status: z.enum(["success", "error"]),
message: z.string().optional(),
data: pageDataSchema.optional(),
})
.parse(raw);

type PageResponse = ReturnType<typeof parsePageResponse>;

const json = parsePageResponse(await response.json());


Тип ответа берём из ReturnType парсера (или из схемы через z.infer), а не пишем отдельно руками (не хардкодим).

Тот же приём работает не только для JSON: куки, query, localStorage, postMessage, FormData - всё, что пришло "извне".

Научите ваших агентов.
  • 🔥 5
  • 😈 2
Post #154 177

Forwarded from Денис Ломов

Код больше ничего не стоит. А разработчики?

Вышел шестой выпуск ЛОМОВА. В гостях Глеб Михеев, CPO ГигаАгента в Сбере, ex-сооснователь агентства Beta, раньше работал в NVIDIA и Skillbox.

Поговорили о том, что будет с инженерами, когда код практически ничего не стоит. Почему команды сжимаются до одного-двух человек, всем ли разработчикам придется стать техлидами и как вообще учить джунов, если ИИ уже делает работу сеньоров. Ну и почему взрослые инженеры снова сидят за кодом до трех ночи, как в детстве.

Отдельно поговорили про агентства. Мы 15 лет строили бизнес на продаже времени людей, а теперь это время стремительно дешевеет. Что будет с агентствами дальше? Глеб даже разобрал, что конкретно поменял бы в Red Collar.

А еще обсудили агентную экономику, где ИИ сам договаривается, покупает, продает и решает задачи за людей. И тут уже вопрос ко всем нам: а что вообще останется делать человеку?

Получилось больше двух часов разговора про будущее, которое уже наступает. И далеко не всем это будущее понравится.

Смотреть новый ЛОМОВ: https://youtu.be/d8C1cqBvw0I

Выпуск на YouTube и VK Видео, слушайте в Apple Podcasts, Spotify, Яндекс Музыке, VK Музыке и Telegram 💪

Особенно рекомендую тем, кто уверен, что его профессию ИИ точно не затронет
Post #153 172
Глеб выдал базу про то, что будет с профессией разработчика в AI эру (все не так плохо). Рекомендую к просмотру
Post #152 260
Программисты - В С Ё

Все разработчики теперь по большей части менеджеры, архитекторы и системные аналитики, по крайней мере к этому все движется. Код пишут агенты, это - реальность, которая случилась. К этому можно по-разному относиться, но очевидно, что индустрия разработки уже не будет прежней. Девальвация нашего с вами опыта - свершившийся факт. Выгорание становится нормой, люди уходят из профессии, потому что у них отняли то, что было источником удовольствия. Можно погрустить по этому поводу, а можно принять и пойти дальше.

Я давно не писал код руками "от и до", лишь изредка могу что-то поправить, потому что так быстрее. Теперь мы пишем (ну как пишем... генерируем) харнесс вокруг агентов. Дистилляция опыта, выработанных и адаптированных паттернов за всю карьеру, их переработка в правила линтеров, примеры и референсы для агентов, скрипты и скиллы. Так как теперь код создается агентами, моя задача - не допустить отклонений от заданных стандартов. Откровенный слоп никому не нужен.

В этом канале я делал упор на различные техники и приемы для креативной разработки. Дальше, помимо этого, будет много постов про AI через призму моего опыта - как AI влияет на эти процессы, что теперь становится возможным, как не допускать слоп, как не терять контроль (хотя это спорный вопрос, может все-таки стоит уже довериться?..), обзор полезных, на мой взгляд, инструментов.

Какие ваши мысли по этому поводу? Го срач в комментах. Можно просто написать, про что было бы интересно почитать.

P.S. Посты в последнее время только по праздникам, сорри. Будет почаще, в целом темы накопились.
  • 🔥 20
  • 😢 4
  • ❤ 1
  • 😭 1
Post #147 602
https://specification.website/

Спецификация технических деталей, которые должны быть реализованы на "хорошем сайте".

Здесь есть как база, как и разделы про производительность, доступность, безопасность, приватность, устойчивость и даже про доступность для AI агентов.

Тут даже есть MCP сервер: можно просто дать агенту ссылку на сайт, и он проведет аудит и предложит улучшения. Прикольно.
The Website Specification A platform-agnostic, full specification of the technical features a good website should have. Built in the open under an MIT licence.
  • 👍 4
  • 🔥 1
Post #146 594
😧😧😧
  • ❤ 13
Post #145 722
Я обновил сайт-портфолио

Прошлый сайт был собран буквально «на коленке», теперь дошли руки сделать по уму.

Я хотел разрушить миф о том, что WebGL и хорошая оценка в PageSpeed/Lighthouse несовместимы: сайт выдает почти соточку как на мобилке, так и на десктопе (есть нюанс: PageSpeed Insights получает таймаут от моего сайта, не знаю в чем причина, может вы подскажете?).

Технологии:

- Astro
- Three.js (TSL)
- Web worker
- View Transition API
- GSAP

Интересные моменты:

- Первый раз использовал View Transition API на полную катушку. Понравилось! Все очень плавно и отзывчиво.
- Абсолютно весь WebGL опыт в веб-воркере, включая видео. Ранее видео было единственным, что не давало запускаться в воркере, потому что была привязка к DOM у VideoTexture. Но начиная с three.js 0.173 появился VideoFrameTexture, который работает без DOM. Фреймы летят через postMessage в воркер.
- Адаптивные видео. Вы знали что атрибут media работает и для <video>? Шок :)

Жду когда еще релизнут HTML-in-Canvas API, тогда доработаю еще, хочется с текстами что-то поинтереснее сделать

Live: https://pavelmazhuga.com/
Source code: https://github.com/pavel-mazhuga/portfolio
  • 🔥 25
  • ⚡ 2
  • ❤ 2
  • 😈 1
Post #143 706
ActiveFrame

Бывает задача привязать к скроллу прогресс видео для вовлечения пользователя в какой-то сторителлинг. Скроллишь вниз - видео покадрово проигрывается вперед, скроллишь вверх - проигрывается реверсивно. До сих пор такая фича делалась двумя способами (я знаю лишь два):

1) через секвенцию изображений: нарезается миллиард файлов, 1 файл = 1 кадр, и по прогрессу скролла в канвас рисуется нужный кадр.

В чем недостаток: очень много кадров, сеть забита кучей запросов, каждый рендер в канвас вызывает декодирование изображения (дорогая операция каждый фрейм). Пример на Codepen

2) через видео: видео специально подготавливается через ffmpeg, затем currentTime подгоняется под прогресс скролла. Пример на Codepen

В чем недостаток: большой вес видеофайла. Нельзя использовать в веб-воркере (привязка к DOM API в виде элемента <video>). Неидеальная синхронизация.

Теперь есть третий способ. Luigi De Rosa, Interactive Director из Active Theory, заопенсорсил ActiveFrame - JS библиотеку и пайплайн для генерации видео в специальном формате .af для декодирования в браузере через WebCodecs API без использования тега <video>.

Это очень круто. Наконец-то нормальный способ скраббить* видео по скроллу!

Преимущества:

- Нативен в WebGL/WebGPU. ActiveFrame декодирует видео через WebCodecs API и отдаёт готовый VideoFrame, который WebGL/WebGPU и канава принимают напрямую, без лишних копий данных.

- (!) Работает в веб-воркере. Нет привязки к DOM, <video> не используется.

- Hardware accelerated. Декодирование идёт через WebCodecs, который использует аппаратный декодер видеокарты (H.264/H.265), то есть это намного быстрее и меньше нагрузка на CPU. Стандартный <video> тоже это умеет, но у него нет доступа к отдельным кадрам.

- Оптимизирован специально под скраббинг*. Обычный <video> при этом тормозит: начинает буферизовать, теряет кадры. ActiveFrame упакован так, чтобы такие операции были отзывчивыми.

- Идеальная синхронизация нескольких видео. Синхронизировать несколько <video> элементов невозможно: у каждого своя буферизация, небольшие рассинхроны неизбежны. Я как-то пытался сделать анимированный переход между страницами, где надо было на новой странице восстановить кадр проигрываемого видео с прошлой страницы кадр в кадр, ничего не получилось. ActiveFrame позволяет напрямую управлять кадрами через setFrame().

Я уже попробовал на реальном проекте, работает прекрасно. Единственный нюанс: в Firefox декодинг хуже работает, надо генерировать видео с всеми ключевыми кадрами (для chrome/safari достаточно чтобы каждый пятый кадр был ключевым), чтобы норм скроллилось, но вес файла раздувается в 4 раза.

Скроллинг - лишь одно из применений. Рандомный доступ к любому кадру открывает множество возможностей, на что хватит фантазии. Чуть позже сделаю свою демку, чтобы показать.

Демо: https://activetheory.github.io/activeframe/
Ссылка на Github: https://github.com/activetheory/activeframe
Пост Luigi в X: https://x.com/luruke/status/2037511335257223626?s=46&t=5F8sSxrCn_V01Wdack1foQ

*Scrubbing - перебор кадров
  • 🔥 21
  • ❤ 3
  • 😈 1
Post #142 498
Павел Мажуга | Frontend Developer Мой первый PR в three.js! Хоть это и одна строчка 🙂 На работе столкнулся с тем, что тридэшечка перестала работать на стареньком iPad, когда я начал использовать ImageLoader для чтения данных с текстуры. Залез в исходники трехи в самом проекте, нашел баг…
Это второй (c)

Еще один PR в трешку:) снова связан с использованием в воркере - TextureLoader использует window, что работает только в основном потоке. Использование ImageBitmapLoader решает проблему.

https://github.com/mrdoob/three.js/pull/33279
GitHub Bayer node: fix web worker usage by pavel-mazhuga · Pull Request #33279 · mrdoob/three.js TextureLoader is not compatible with worker environment, so ImageBitmapLoader should be used instead. This PR solves the issue by checking the environment and picking the appropriate loader.
  • ❤‍🔥 7
Post #141 561

Forwarded from 🦜 on the web

Basewatch
Инструмент для отслеживания изменений в web-platform и браузерной поддержке.
Помогает понимать, какие фичи стали baseline и когда их можно безопасно использовать в продакшене.
Полезен для принятия решений о внедрении новых API без лишнего риска.

Используемые источники это MDN Browser Compat Data, CanIUse, Web Platform Baseline, Chrome Status.

Также можно подписаться на отслеживание конкретных фич, когда поддержка достигнет определенного процента.
basewatch.dev BaseWatch — Get Notified When CSS Features Reach Baseline Track CSS, JS & HTML browser support. Get email alerts when features hit your chosen support threshold. Free, no account needed.
  • 🔥 7
Post #139 631
Борьба с «лесенкой» у градиентов в шейдере

Градиенты на темных фонах часто превращаются в «лесенку» (banding). Так происходит из-за нехватки точности 8-битного цвета для отображения очень плавных переходов. Это видно на первом скрине (я надеюсь что видно, скрин плохо передает, выкрутите яркость на максимум и увидите).

Это можно решить с помощью дизеринга (dithering): мы подмешиваем к цвету небольшой нойз, который визуально размывает границы «лесенки».

Дизеринг можно реализовать вот так (TSL):


const dither = (node) => {
const noise = viewportUV
.mul(viewportSize)
.dot(vec2(12.9898, 78.233))
.sin()
.mul(43758.5453)
.fract()
.sub(0.5)
.div(255);

return node.add(noise);
};


Вычисляем псевдорандомный шум на основе координат пикселя и прибавляем его к итоговому цвету перед выводом. Деление на 255 гарантирует, что шум не зернит, а мягко перемешивает соседние оттенки. Результат на втором скрине.

Подробнее можно почитать тут: https://alex-charlton.com/posts/Dithering_on_the_GPU/

Практическая статья от Maxime Heckel: https://blog.maximeheckel.com/posts/the-art-of-dithering-and-retro-shading-web/
  • 🔥 8
  • 😈 3
  • ❤ 1
Post #137 556
Паттерны во фронтенде

https://www.patterns.dev/vanilla/

Ресурс о дизайн-паттернах, паттернах рендеринга и производительности для построения веб-приложений на чистом JS или фреймворках (react / vue).

Прикольно, что некоторые разделы содержат сэндбоксы с кодом и много графического контента
  • ❤ 11
Post #136 547
Web Haptics

Web Haptics - это технология, позволяющая веб-сайтам использовать тактильную отдачу (вибрацию) мобильных устройств для улучшения UX. Она имитирует физический отклик некоторых элементов. Вы могли это замечать, например, в инсте, когда в директе оверскроллите вниз - так можно включить режим исчезающих сообщений.

Для вызова используется Vibration API (navigator.vibrate): позволяет задавать одиночные импульсы или сложные паттерны вибрации (например, чередование вибрации и пауз). Хорошо работает на Android, а вот на iOS Vibration API блокируется системой.

В твиттере нашел либу https://haptics.lochie.me/, которая использует забавный костыль:

В мобильном iOS поддерживает хаптики только чекбокс. Поэтому либа создает скрытый чекбокс по триггеру, нажимает его и сразу удаляет. Я бы применил где-нибудь на проекте, прикольно
WebHaptics WebHaptics – Haptic feedback for the mobile web.
  • 👍 14
  • 😈 2
  • ❤ 1
Older posts →

About this channel

How can I read @mazhugagl without a Telegram account?
TGViewer shows the public web preview Telegram publishes for Павел Мажуга | Frontend Developer: recent posts, photos, videos and the subscriber count, with no app, login or account.
How many subscribers does Павел Мажуга | Frontend Developer have?
Павел Мажуга | Frontend Developer (@mazhugagl) has 373 subscribers on Telegram, refreshed roughly every 30 minutes.
Does Павел Мажуга | Frontend Developer know I viewed it here?
No. Public channel previews carry no viewer identity, and TGViewer has no accounts or tracking of what you look up.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →