Стендап Сьогодні

Що я зробив, що я хочу зробити, і що це все значить.
Повсякденні здобутки в форматі стендапу.
Детальніше в статті

Підписатись на RSS
📢 Канал в Telegram @stendap_sogodni
🦣 @stendap_sogodni@shevtsov.me в Федиверсі

15.05.2023

Враження від Greensock

…Вчорашнє розуміння про Greensock доповнилось сьогодні тим, що в onUpdate краще зовсім нічого не перераховувати — саме тому, що ця функція може бути викликана в неочікуваний час та в невизначеному порядку. Як тільки переніс всі обчислення з onUpdate в render, відразу зникли баги. А то було таке, що в прямому порядку анімація проходить нормально, а у зворотному — бардак.

Тож тепер підхід такий: Greensock собі анімує все, що потрібно, а потім я в функції render оновлюю сцену відповідно до поточної мітки, переношу значення в потрібні місця, та, власне, потім роблю малювання. Тепер все передбачувано.

Після цього відчувається користь від бібліотеки: рівень абстракції підвищився. Більше не потрібно думати про стикування частин та про перенос глобальної позиції в локальну до етапу. Можна легко додавати до анімації нові етапи та експериментувати (краще наближати камеру та повертати одночасно? або послідовно? )

Наступним кроком, знайшов ресурс Natural Earth, на якому містяться, окрім іншого, бази даних по різних географічних обʼєктах. Мені цікаві кордони держав та міста. Все це можна завантажити в невідомому мені досі форматі shapefile, до якого, на щастя, є парсери як для JavaScript, та і для Go.

PS: а знаєте, що офісне крісло може вимикати монітор? В цьому винний електростатичний розряд, який створює механізм підйому. Звучить нереально, але в мене таке дійсно відбувається час від часу — встаю з крісла та монітор вибиває. Якби не натрапив випадково на пост, то це б залишалось таємницею. А так, спробую замінити кабель до монітора.


14.05.2023

Бібліотека анімації Greensock

Відкриття дня - бібліотека Greensock. Вона надає зручну структуру для анімації. Я вже мало не написав свою, але випадково побачив в прикладах Greensock та, на щастя, це саме те, що мені було потрібно.

В чому моя задача? Анімація з декількох етапів потребує відстеження як поточного етапу, так і положення в ньому. Greensock дозволяє задавати ці етапи декларативно, та сама бібліотека піклується про їх впорядкування. До речі, вона підтримує й анімацію прокруткою, якою я займався вчора. І помʼякшення анімації вбудоване.

Як воно працює з Three.JS? Взагалі вся анімація являє собою інтерполяцію значень. В базових прикладах по Greensock значення містяться в СSS, але насправді вона вміє інтерполювати будь-які числові атрибути довільного обʼєкту. В тому числі, й векторів Three.JS - або просто звичайних обʼєктів, якщо це зручно. Коли над значеннями, що інтерполюються, потрібно проводити додаткові дії, то їх можна описати в функції onUpdate.

Що мені не дуже подобається: інтерполювати можна тільки по одному обʼєкту, а з Three.JS зазвичай треба комбінувати декілька (або навіть просто position та rotation). В такому випадку створюю окремий обʼєкт-ціль інтерполяції, а з нього вже в onUpdate розкидую значення куди треба.

Ще довго шукав, як же ж робити переходи від сцени до сцени, тобто наприклад з глобуса на карту. Це ускладнюється ще й тім, що з анімацією за прокруткою цей перехід може трапитись в обидва боки. А ще, як виявилось, функція onUpdate може викликатись не тільки для поточного етапу, тому там не можна робити логіку визначення сцени. Потім знайшов систему міток та функцію currentLabel, яка саме відстежує поточний етап анімації. Тут ідея така: під час render перевіряю поточну мітку, та готую сцену для неї, якщо мітка помінялась.

3D-графіка - приємна розвага після системного програмування, поки не примушує згадувати про всякі векторні добутки та кватерніони, про які я вже років 15 не чув.


13.05.2023

Анімація за прокруткою

Черговий прогрес по тревел-постам — реалізував анімацію карти за прокруткою. Подивився оцю нещодавню статтю з NYTimes та зрозумів, що саме цього не вистачало для режисованого, але все ж контрольованого користувачем відображення. (Анімація, яку я маю на увазі, починається після перших параграфів статті, до неї треба ще докрутити.)

Як я це робив. Щоб реєструвати прокрутку, роблю елемент необхідної висоти — саме його фізичний розмір буде визначати тривалість анімації. Всередину розташовую власне полотно. Полотно за розміром збігається з вікном. Його позиціювання залежить від положення прокрутки — це або абсолютне позиціювання нагорі чи внизу контейнера, або — повноекранне fixed, при якому й відбувається анімація.

Щоб стежити за прокруткою, слухаю звичайну подію scroll. Щоб заощадити ресурси, це робиться тільки тоді, коли елемент з картою видимий; для цього існує цікавий клас IntersectionObserver.

Далі позиція прокрутки перекладається на відсоткову, і починається цікава частина. До цього часу моя анімація була повністю заскриптована, та просувалась за допомогою requestAnimationFrame. Натомість для анімації за прокруткою необхідно задати функцію стану сцени від часу. Я майже все так і робив, от тільки з обертанням карти вийшли деякі складнощі. Окремо треба описати переходи від сцени до сцени, як в прямому, так і у зворотному напрямку — додавання та видалення обʼєктів.


12.05.2023

Команда apt-get satisfy та інші цікаві пакетні менеджери

Дізнався на днях про команду apt-get satisfy. Нею можна вказати версію пакета приблизно, як я це звик робити в Rubygems або NPM. Наприклад: apt-get satisfy 'knot-resolver (>=5.6.0)'. Мені це було потрібно, щоб переконатись, що правильна версія пакета буде встановлена в докерфайлі. Взагалі лінтер hadolint радить вказувати версію явно. Але при такому підході докерфайл доведеться міняти, коли версія пакета в репозиторії оновиться — чого я не хочу робити без потреби.

Команда ця чомусь мало відома, навіть довелось відповісти про неї на Ask Ubuntu річної давнини. Зʼявилася вона десь у 2019 році.

Якщо вже зайшло про пакетні менеджери, то на Windows необхідно знати про chocolatey. Завдяки цій програмі можна як встановити, так і оновити багато популярних додатків автоматично. Особливо це корисно для налаштування компʼютерів родичам. Замість того, щоб лазити по системі та оновлювати все підряд, достатньо один раз запустити choco upgrade. Так само однією командою можна встановити пачку необхідних програм.

А на macOS є Homebrew Cask. Я їм не користуюсь, але тільки що перевірив та там є чимало додатків — більше, ніж я думав — наприклад, ось Setapp.

Чим я на Маці користуюсь, то це додатком MacUpdater. В нього зворотний підхід — він сам знаходить в системі всі встановлені додатки, та вміє їх оновлювати. Це набагато ефективніше, ніж погоджувати оновлення кожного додатку окремо. Також не так давно зʼявилася можливість завантажувати та встановлювати додатки. Але все це MacUpdater робить в напівавтоматичному режимі, тому розгорнути пачку додатків однією командою не вийде.

…А ще MacUpdater теж є на Homebrew Cask. We need to go deeper!


11.05.2023

На що гарний Golang у вебдодатках?

Я вже писав статтю про те, на що гарний Ruby on Rails, та я все ще вважаю Rails правильним вибором для вебдодатка. Тобто, якщо додаток написаний на Rails, то скоріше за все не доведеться його переписувати на щось інше.

Але уявимо, що вам треба переконати мене, що додаток треба писати на Go, а не на рельсі. Ой, важко це буде зробити. Бо Go не підготований для створення вебдодатків. Починаючи з того, що мова ця не така гнучка (див. статтю). Але також, на Go не вистачає відразу декількох інструментів, які є в Ruby on Rails. Це й міграції для бази. Й шаблонізатор. Й інтеграційні тести. І це тільки те, чого мені найбільш не вистачає. Писати вебдодаток на Go - технічно можливо, але безглуздо.

Тому пропоную дивитися на роль Go інакше, та переписувати на Go свою базу даних. Бо сильна сторона Go - це утримання складного та великого стану.

В Rails ми делегуємо утримання стану на базу даних. На такому розділенні праці побудований весь сучасний інтернет — тож можна сказати, що воно надзвичайно ефективне. Втім, зустрічаються випадки, коли база не справляється з потребами додатка. Може, бізнес-логіка надто складна, може, обмеження швидкодії не влаштовують. В таких випадках можна пошукати іншу базу, та я б це й радив робити. Можна почати програмувати всередині бази, це теж працює.

Але програмування в базах даних, порівняно зі звичайним, суцільний жах. Тестів немає, деплою немає, і так далі. Тому простіше було б реалізувати логіку стану безпосередньо в додатку. Ось тут вже можна впевнено брати Go. В Go чудова модель рівночасності, яка дуже корисна для керування складними структурами стану. Зробити власну базу легше, ніж здається, бо універсальна база нам не потрібна — тільки те, що використовує додаток. Власне, так NoSQL бази й зʼявляються.

(Звісно, це не єдине застосування Go. Я міркую з боку вебдодатків.)


10.05.2023

Точна перевірка як антипаттерн

Виявив, на велике диво, що в нас в черзі задач бовтається задача ще з лютого місяця. Причиною стало особлива бізнес-логіка, по якій задача має N шансів отримати помилку та спробувати пізніше, а на N+1 спробу повинна видати “жорстку” помилку та остаточно закінчитись. (Так, зазвичай черги мають таку функцію вбудовану, але тут не зовсім стандартна черга.)

За цією логікою, задача не могла залишатись в черзі більше як добу. Що трапилось? Умова остаточного виходу була з перевіркою на рівність: attemptNumber == N+1. Через незрозумілу мені ситуацію, логіка на N+1 спробі не спрацювала — скоріш за все, команда на видалення з черги не була опрацьована. Та на N+2, N+3, N+100-й спробі задача призводила тільки до “мʼякої” помилки.

Інтуїтивно мені завжди хочеться зробити максимально чітку перевірку — якщо я знаю, що гілка має трапитись на N+1 спробі, то так і треба написати? Власне, сьогоднішній випадок показує, що ні. Треба осягнути всі можливі значення змінної, та визначити, що має трапитись в кожному. Тут у нас є дві множини значень, які розгалужують логіку. Все, що до N, створює “мʼяку” помилку. Все, що після N, створює “жорстку”. Саме це й має висловлювати умова: attemptNumber > N.

…Окремий випадок — це дробові числа. Їх взагалі не можна надійно порівнювати точно через особливості обчислень з рухомою комою. Підійде або наближене порівняння: abs(a-b) < EPSILON, де EPSILON - незначне маленьке значення, або ж, знов-таки, порівняння більше/менше.


09.05.2023

Останні, поки що, міркування про ВР

Пройшов Half-Life: Alyx, потім подивився відео як воно з шоломом грається (бо тепер без спойлерів)… Ну так, безперечно, суть цієї гри саме в ВР. От, наприклад, щоб відкрити ящик з припасами, треба розвʼязати простеньку головоломку на повертання кулі. В моді без ВР такі ящики відкривалися просто кнопкою. З іншого боку, стрілянина досить примітивна, що особливо помітно на кінці гри, коли її стає багато. Зброї, як виявилося, всього три різновиди, тобто ніякої тактичної глибини немає. Як шутер, гра на четвірку з мінусом.

Проте я радий, що вдалося пограти, побачити сюжет та краєвиди. Бо моя головна проблема з Half-Life: Alyx була в тому, що ВР мені не цікавий, а тут виходить, що команда Valve вирішила вкластися саме в ВР-гру. Хоча, на цей час, можна сказати, що ВР стає більш нішевою технологією, а не такою, що замінить ігри на моніторі та телевізорі. (Та насправді найбільше гравців та грошей зараз в смартфонах.)

Чому не люблю ВР? Головним чином, не хочу бути ще більше ізольованим від світу — чесно кажучи, проводити час абсолютно зануреним в гру мене навіть лякає. Я й так багато часу сиджу за екраном. Також, хоч ВР й збільшує занурення, але через це суттєво обмежує потенціал ігор. Мої улюблені жанри (а саме, soulslike та boomer shooter) потребують свободи рухів, яку ВР не може забезпечити. Та чого там, навіть стрибати по Morrowind зі швидкістю коня у ВР не вийде. Тому тенденція переходу ігор у ВР мене тривожила. Поки ця тенденція була. Але зараз виглядає так, що ВР буде розвиватися своїм шляхом та розкривати свій унікальний потенціал.

Взагалі, як користувачу, мені більше цікава доповнена реальність. Під якою я маю: реальність, на яку накладаються “живі” цифрові елементи. Причому, бажано, не окулярами чи шоломом, а саме вкрапленнями цифрового змісту — яких в нас вже й так багато, від екранів телефонів до транспортних табло, реклами та навіть світлофорів. Такого я б хотів бачити більше. Не шоломів.


08.05.2023

Як зібрати гаражний VR-комплект за декілька тисяч гривень

…Насправді це моя друга спроба пограти в Alyx. До цього я зібрав собі VR “з підручних засобів” та навіть успішно… Було це ще у 2020-му, карантин, робити не було чого. Ось стисла інструкція:

Озброєний таким комплектом, я пограв може з пару годин. Напевно, розвʼязувати цю задачку було цікавіше, ніж користуватись. Не повторюйте це вдома.


07.05.2023

Half-Life: Alyx без ВР

👓 Сьогодні нарешті довелося пограти в Half-Life: Alyx. Специфіка цієї гри в тому, що вона вимагає шолом віртуальної реальності. Я люблю халф-лайф, але не настільки, щоб купувати коштовне залізо. Натомість натрапив на мод HLA-NoVR, який повертає Half-Life: Alyx назад до форми звичайного шутера. І шутер виходить пречудовий.

Одним словом, якщо тобі подобаються шутери, то Half-Life: Alyx з модом HLA-NoVR рекомендую всім серцем. Атмосфера та графіка на висоті. Геймплей не гірше ніж, скажімо, Resident Evil 8 (тобто шутер “з елементами виживання”).

Само собою, елементи, що спираються на віртуальну реальність, в більшій частині втрачені. Не доведеться перезаряджати руками рушницю, копатися у смітті та малювати віртуальним маркером по віртуальній дошці. Взаємодія з простором нагадує ігри серії Amnesia. Деякі головоломки очевидно прибрані за неможливістю. Тож треба признати, що правильний спосіб пережити HL: Alyx - це з шоломом, та нічого його не замінить.

Проте, як виявляється. окрім атракціону з ВР в Alyx міститься й повноцінний шутер. Причому як я уявляю, кращій, ніж у ВР, бо має нормальне WASD переміщення, а не ВР-телепортацію, як можна побачити на цьому відео. Чесно, не можу уявити, щоб телепортація якось покращувала геймплей шутера.

Де гра видає свою природу. Патрони та аптечки на екрані виглядають ну дуже маленькими, та за ними доводиться полювати мишею. Платформінг не ідеальний — бо у ВР з платформи на платформу просто тривіально телепортуєшся, от і не тестували. Так само, зустрічаються місця, де підлога не рівна, а заставлена декораціями, та через колізії по ній доводиться bunny-hopати - у ВР нема вільного переміщення, та цього не помітиш. Але в цілому, якісний захопливий шутер, в який можна грати хоч цілий день, на відміну від ВР.


06.05.2023

Скомбінував глобус та карту

Скомбінував глобус та карту в єдину сцену. Вийшло саме так, як я собі уявляв, хоча анімація поки базова та не вистачає відміток.

Найскладніший аспект всієї цієї задачі — це орієнтація в системах координат. Наприклад, в програмуванні всі звикли, що перша координата (i) йде вниз, а друга (j) - ліворуч. Але в графіці перша координата то x, а y йде знизу вгору. Коли доводиться генерувати площини та відкладати текстурні координати, то мозок просто ламається. Потім по багато разів передивляєшся код, щоб ніде не було помилок.

Ще — виявилося складним зробити, щоб карта на глобусі відповідала локальній. Якщо в глобусі мало трикутників (наприклад, 2000), то проєкція викривляє текстуру, чого не помітиш, поки не буде потреби “влучити” в точку з точністю до кілометрів. Це вирішується збільшенням кількості трикутників; але в ідеалі, щоб спростити сцену, в міру наближення до точки від глобуса має залишатися дедалі менший шматочок з дедалі більшою деталізацією.

Для того, щоб нормально стилізувати стежку, є клас Line2 - бо стандартна лінія може бути тільки шириною в один піксель. У Three.js багато таких “прикладів”, що часто містять бібліотеку, яку можна використати в власних проєктах.

Нарешті, за допомогою бібліотеки suncalc я визначаю розташування сонця в день походу та емулюю його джерелом світла. Дрібниця, але мені приємно. Та й робиться просто — оскільки карта вже зорієнтована так, що вісь Y вказує на північ, то сонячні азимут та висота збігаються зі стандартними сферичними координатами 𝜑 та 𝜃.