BT – тулчейн баннерной разработки

Ранее я обещал рассказать о своем новом проекте, не связанном с D – выполняю обещание. Волею судеб несколько лет назад я стал профессиональным баннермейкером. Это разновидность фронтенд-разработки на стыке с анимационным дизайном – чаще всего я делаю HTML-баннеры и виджеты с разнообразной анимацией, эффектами и интерактивными механиками. Поскольку почти все рекламные сети имеют ограничение для баннеров по весу (и довольно серьезное – обычно 150 кб), эта профессия еще и пересекается в какой-то степени с демосценой, где на первом месте – искусство минимизировать информацию и генерировать ее процедурно.

Баннеры – это обычные HTML-странички, которые показывают пользователю рекламный сюжет и содержат ссылку на сайт рекламодателя. Они могут быть изготовлены при помощи самых разных инструментов, в том числе визуальных (Adobe Animate, Google Web Designer), но самое гибкое решение – писать непосредственно на HTML и JavaScript, рисуя графику либо обычными элементами DOM, либо через canvas. Благодаря отказу от Animate, вы не привязаны к его JS-библиотеке, которая сама по себе сжирает много веса, если ее нужно приложить к баннеру локально. Однако для отрисовки мало-мальски сложной анимации одним CSS вы не обойдетесь, и вам нужны такие библиотеки, как GSAP, Anime.js и др. – благо, весят они совсем немного. Основная сложность – уместить все ресурсы баннера в те самые 150 кб, что порой представляет нетривиальную задачу.

Для решения этой и многих других задач, которые возникают при разработке HTML-баннеров, я написал на Node.js комплект инструментов BT (Banner Toolchain). Его идея уходит корнями во внутренний инструментарий компании SmartHead, которым я пользовался три года и решил переделать полностью с нуля, уже в качестве независимого проекта с более эффективной реализацией большинства фич.

BT – это локальный сервер, предназначенный для разработки одностраничных сайтов с упором на минимизацию веса всех ресурсов. Например, в нем есть встроенный оптимизатор изображений, генератор CSS-анимации, функция записи баннера в GIF и видео, а также сборщик для подготовки баннера под все популярные рекламные площадки и упаковки в архив.

(далее…)

Веб-мусор

Когда я захожу на какой-нибудь сайт и вижу что-то из перечисленного ниже, у меня пропадает всякое желание заходить второй раз. Большая просьба ко всем вебмастерам: смело используйте эти элементы, если вы хотите отпугнуть посетителей и вызвать к себе тонны ненависти!

  • Реклама по площади больше, чем полезный контент, а также перекрывающая или блокирующая контент. И еще любая реклама со звуком, самопроизвольное перенаправление по партнерским ссылкам и открытие дополнительных вкладок/окон с рекламой.
  • Блокировка доступа к сайту при включенном Адблоке. Я еще не решил, полезен ли для меня ваш сайт, а вы уже хотите на мне заработать? Если реклама для вас жизненно важна, просто культурно сообщите об этом, и я отключу блокировщик рекламы – после того, как прочитаю то, что мне было нужно. Но если вы мне сразу не дадите это сделать, то я просто уйду и больше не вернусь.
  • Навязчивые всплывающие сообщения и модальные окна, а также любые посторонние элементы, самопроизвольно блокирующие или мешающие видеть контент – подписка в соцсетях, опросы и т.д. Если я захочу подписаться на вашу страницу в соцсети или пройти опрос, я это сделаю без вашего напоминания.
  • Блокировка копирования текста или правого клика на изображениях. Напрасно стараетесь – все равно и текст, и изображения легко вытащить из HTML. За кого вы принимаете своих посетителей, за полных идиотов?
  • Требование ввести капчу просто для доступа к сайту (не для регистрации или авторизации).
  • Игнорирование HTML5 (верстка, целиком выполненная на Flash, видео или аудио на Flash).
  • Автоматически воспроизводящаяся фоновая музыка, особенно если она не выключается.
  • Атоматически запускающееся видео – это даже хуже музыки, но, увы, в последнее время куда популярнее.
  • Тексты не в UTF-8. Я этих ужасов с кодировками наелся в нулевые.
  • DRM в любой форме. Если я не смогу скачать ваше аудио или видео и посмотреть его локально своим плеером (так, как удобно мне), то не обессудьте – пойду в другое место.
  • Бесконечные ленты, которые рано или поздно начинают подвешивать браузер. Пожалуйста, разбивайте длинные ленты на страницы.
  • Регистрация по номеру телефона, если это не мессенджер (хотя мне и в мессенджерах это не нравится), а также необоснованное требование при регистрации предоставить конфиденциальную информацию (полное имя, адрес проживания, паспортные данные и т.д).
  • Блокировка доступа к сайту из старых или малоизвестных браузеров. Не вам решать за меня, каким браузером пользоваться – могу вообще свой HTTP-клиент написать.
  • Черные списки IP, блокировка выходных узлов TOR и браузерных прокси.
  • Большие файлы без возможности докачки.

Новый сайт Atrium

Обновился дизайн страницы проекта Atrium – http://gecko0307.github.io/atrium.

Пример работы с Yahoo! Finance на D

Пример работы с сетевым API Yahoo! Finance: запрос котировок ценных бумаг. Демонстрирует некоторые распространенные идиомы Phobos – например, форматированный ввод, объекты времени и даты. Использует минималистичный HTTP-клиент DHTTPClient. На ввод программа принимает тикер (биржевое обозначение акции) – например, MGNT.ME для акций “Магнит”. Выводит стоимость, дату и время последней сделки.

module main;

import std.stdio;
import std.string;
import std.uri;
import std.format;
import std.datetime;

import dhttpclient;

struct Quote
{
    string symbol;     // s
    string name;       // n
    double lastTrade;  // l1
    string currency;   // c4
    DateTime datetime; // d1 t1
}

Quote getQuote(string sym)
{   
    const request = "snl1c4d1t1";

    const url = 
        "http://finance.yahoo.com/d/quotes.csv?e=.csv"
      ~ "&f=" ~ request
      ~ "&s=" ~ sym.encode;
    
    auto http = new HTTPClient();
    auto data = http.get(url).chomp;

    Quote q;

    with (q)
    {
        uint year, month, day;
        string time;

        formattedRead(data, 
            ""%s","%s",%s,"%s","%s/%s/%s","%s"", 
            &symbol, &name,
            &lastTrade, &currency,
            &month, &day, &year, &time);

        uint hour, minute;
        formattedRead(time, "%s:%s", &hour, &minute);
        if (time[$-2..$] == "pm")
            hour += 12;

        datetime = DateTime(year, month, day, hour, minute);
    }

    return q;
}

void main(string[] args)
{
    string s = "AAPL"; // Apple Inc.
    
    if (args.length > 1)
        s = args[1];

    auto q = getQuote(s);

    writefln("Symbol: %s", q.symbol);
    writefln("Name: %s", q.name);
    writefln("Last trade: %s %s (%s)", 
        q.lastTrade, 
        q.currency, 
        q.datetime);
}