Inkwash — это одностраничное HTML-приложение, симулирующее акварель в реальном времени. Всё работает через пачку WebGL2-шейдеров, которые крутят небольшой стек текстур RGBA16F. Никаких «пикселей цвета» — только поля плавающей плотности, мокроты и скорости.
В основе лежит алгоритм Stable Fluids Джоса Стема (1999). Его суть — не толкать жидкость вперёд, а на каждом шаге вычислять, откуда она пришла, и тянуть значение оттуда. Это даёт стабильность: даже при низком FPS симуляция не взрывается. Дополнительно шейдеры делают проекцию давления (на грубой сетке 256x256, ~22 итерации Якоби) и добавляют конфайнмент завихренности — чтобы поток не затухал слишком быстро.
Но главное — «бумага». Вода не может течь по сухому месту: скорость умножается на гладкую функцию от поля wetness. Чернила двигаются только там, где мокро. Сама вода испаряется с настраиваемой скоростью (2–18 секунд). Это превращает симуляцию в настоящую живопись: каждое касание — закрывающееся окно, и высыхание замораживает потёки там, где они есть, без переноса пигмента.
Рисование — цепочка гауссовых сплэтов. Штрих пера — это серия чернильных сплэтов, кисть — водяных сплэтов плюс импульсов скорости по ходу движения. Важно: чернила накладываются аддитивно (как лессировка), а вода — через MAX-блендинг, иначе кисть превращала бы бумагу в болото. Нажатие и скорость влияют на толщину и плотность линии. Курсор мягко догоняет руку — это убирает дрожь и даёт естественное последействие.
Самый хитрый трюк — хроматография. Дешёвые чёрные чернила состоят из смеси красителей, и на мокрой бумаге каждый диффундирует с разной скоростью. Inkwash эмулирует это, задавая разный коэффициент диффузии для каждого цветового канала: красный (он же голубой циан) убегает быстрее всего, синий задерживается. В результате у влажной линии появляется тёмный центр и холодный ореол. Регулятор color управляет этим разделением.
Слой «закрепления» (клавиша d) переводит часть подвижных чернил в неподвижный слой — фиксированный. Теперь поверх можно рисовать, не размазав нижний слой. Белая гуашь (альфа-канал) при закреплении не остаётся поверх, а «выжигает» плотность под собой, как настоящая непрозрачная краска. Итог — честная многослойность.
Финальный шейдер отрисовки использует закон Бугера — Ламберта — Бера: цвет = paper * exp(-density). Перекрывающиеся штрихи перемножают пропускание, а не усредняют альфу — поэтому краски не скатываются в грязь. Поверх шейдер добавляет шумы бумаги, грануляцию, эффект тёмного края (реакция на градиент плотности) и влажный отблеск, показывающий, где ещё мокро.
Приложение — один HTML-файл, работает на всём, что поддерживает WebGL2 и EXT_color_buffer_float. На iPad Apple Pencil рисует, а палец — водяная кисть. На Mac с трекпадом — Force Touch для нажима. Весь код сгенерирован моделью Claude Fable 5 от Anthropic. Автор (человек) признаётся, что сам кода не писал, но всё проверил. Единственное, что тормозит, — экспортные ограничения США на эту модель. Но сам проект уже работает, и это круто.