Как я собрал интерактивную черную дыру и квантовую лабораторию в стиле ЦУП 90-х на чистом JS

Привет, Хабр! Я всегда любил физику и ретро-эстетику. Однажды мне захотелось сделать научно-популярный проект, который не просто показывает текст с формулами, а позволяет «покрутить» физику руками. Так появился ЦУП-7 — интерактивный пульт с рендерингом черной дыры на WebGL и пятью квантовыми экспериментами. В этой статье я расскажу, как устроен проект под капотом, с какими проблемами я столкнулся и почему решил отказаться от фреймворков.

1. Черная дыра: WebGL и Метрика Шварцшильда
Главный экран — это не видео и не картинка, а настоящий шейдер. Чтобы свет огибал горизонт событий, я использовал интегрирование геодезических линий методом Рунге-Кутты 4-го порядка (RK4). В коде рассчитывается гравитационное линзирование, эффект Доплера для аккреционного диска и даже фотонное кольцо.
Скрытый текст
* Как работает математика черной дыры (Геодезические)
Чтобы свет огибал черную дыру так, как это предсказывает Общая теория относительности (ОТО), мы не можем использовать обычную евклидову геометрию (где свет летит по прямой). Нам нужно решить уравнение геодезической линии в метрике Шварцшильда.
Вместо того чтобы отслеживать декартовы координаты луча (x,y,z)(x,y,z) шаг за шагом, мы используем трюк из теоретической физики. Мы знаем, что орбита фотона лежит в одной плоскости. Поэтому мы переходим к полярным координатам и используем величину u=1/ru=1/r (обратный радиус).
Уравнение траектории фотона в метрике Шварцшильда выглядит так:
d2udϕ2+u=3Mu2dϕ2d2u+u=3Mu2
(или u′′=−u+3Mu2u′′=−u+3Mu2)
Где:
uu — обратный радиус (1 / расстояние до центра).
ϕϕ — угол поворота луча вокруг черной дыры.
MM — масса черной дыры (в нашем коде M=1M=1).
Слагаемое 3Mu23Mu2 — это и есть эффект ОТО. Если его убрать, получится уравнение прямой линии (классическая оптика).
Как это решается в шейдере?
Аналитического решения у этого уравнения нет, поэтому мы решаем его численно. В коде используется метод Рунге-Кутты 4-го порядка (RK4) — золотой стандарт для физических симуляций. Мы делаем маленькие шаги hh по углу ϕϕ и на каждом шаге вычисляем, как меняется uu и её производная.
glsl
// Упрощенный кусок кода из шейдера
float u = 1.0 / length(ro); // Начальный обратный радиус
float du = -u * vr / vphi; // Производная
float phi = 0.0;
for (int i = 0; i < MAXSTEP; i++) {
// Вычисляем шаг методом RK4
float k1w = -u + 3.0 * M * u * u;
// ... (промежуточные вычисления k2, k3, k4) ...
u += h * (k1u + 2.0 * k2u + 2.0 * k3u + k4u) / 6.0;
du += h * (k1w + 2.0 * k2w + 2.0 * k3w + k4w) / 6.0;
phi += h;
}Как только uu становится слишком большим (луч пересек горизонт событий, r≤2Mr≤2M), мы останавливаем цикл. Если луч улетел бесконечно далеко, мы берем его финальный вектор направления и рисуем на его месте звезды.
* Аккреционный диск: Доплер, красное смещение и турбулентность
Аккреционный диск — это раскаленное вещество, вращающееся вокруг дыры. Рендеринг диска — самая зрелищная часть шейдера, но она требует учета нескольких релятивистских эффектов.
* Пересечение плоскости
Пока луч летит, мы проверяем, не пересек ли он экваториальную плоскость (y=0y=0). Если пересек, мы берем радиус rr в этой точке и сэмплируем диск.
* Вращение и эффект Доплера
Диск вращается по кеплеровской орбите (быстрее у центра, медленнее на окраинах). Из-за этого часть диска летит на нас, а часть — от нас.
Скорость движения вещества: β=M/rβ=M/r.
Эффект Доплера: свет от приближающейся стороны становится ярче и «синее», от удаляющейся — тусклее и «краснее».
В коде это считается через фактор δ=1/(γ(1−β⃗⋅n⃗))δ=1/(γ(1−β⋅n)), где γγ — Лоренц-фактор.
* Гравитационное красное смещение
Фотону нужно потратить энергию, чтобы выбраться из гравитационного колодца. Поэтому свет с окраин диска кажется краснее, чем с внутренних краев.
Фактор замедления: z=1−2M/rz=1−2M/r.
* Температура и цвет
Мы не задаем цвет диска вручную. Мы считаем его температуру по закону Стефана-Больцмана. Температура падает с радиусом: T∝r−3/4T∝r−3/4. В коде есть функция blackbody(T), которая по температуре (с учетом сдвигов Доплера и гравитации) вычисляет реальный RGB-цвет.
* Турбулентность (Шум)
Чтобы диск не выглядел как плоский блин, мы накладываем на него 3D-шум (FBM — фрактальный броуновский шум). Луч проходит сквозь разные слои «газа» на разных радиусах и углах, накапливая яркость (альфа-блендинг). Именно поэтому у диска есть объем и закрученные вихри.
* Итог: Почему это работает быстро?
Секрет в том, что мы вообще не используем полигоны (треугольники) для черной дыры. Каждый пиксель на экране — это независимый математический расчет (Raymarching). Видеокарта просто запускает этот шейдер параллельно для миллионов пикселей, выдавая 60 кадров в секунду даже на встроенной графике.
2. Квантовые эксперименты
Внутри — 5 симуляций (Квантовый ластик, Бомба Элицура-Вайдмана, Две щели, Отложенный выбор и Парадокс близнецов).Самое сложное было визуализировать квантовую запутанность в «Квантовом ластике» на Canvas 2D. Пришлось генерировать события так, чтобы при фильтрации по идлерам (D1/D2) на экране D0 собиралась интерференционная картина.


3. Дизайн: ЭЛТ-монитор и ЦУП 90-х
Я хотел, чтобы сайт ощущался как старый пульт управления. За это отвечают:
Шрифт Courier New и фосфорно-зеленый цвет.
Наложение скан-линий (CSS
repeating-linear-gradient).Звуки. Фоновая телеметрия черной дыры и писк при наведении на кнопки.
Пасхалка.
4. Технический стек (или его отсутствие)
Проект написан на чистом HTML, CSS и JavaScript. Без React, без Webpack, без npm-пакетов. Всё летает благодаря нативному Canvas 2D и WebGL. Сайт полностью статический, хостится на GitHub Pages и поддерживает два языка (RU/EN) с переключением на лету.
Заключение:
Проект доступен по адресу blackh0le.ru. Он бесплатный, открытый (ссылка на GitHub) и работает даже на телефонах. Буду рад фидбеку от сообщества физиков и фронтендеров!
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.