300 симуляцій — чого ми навчились, створюючи найбільшу WebGL-бібліотеку фізики

Два з половиною роки, 300 симуляцій, 78 категорій, дві мови. Ось що пішло правильно, що б ми зробили інакше, 5 найскладніших симуляцій, які ми коли-небудь випускали, і архітектурні рішення, що визначили все інше.

300
інтерактивних симуляцій
78
STEM-категорій
2.5
роки загалом

5 найскладніших симуляцій, які ми випустили

Більшість симуляцій займають день-два: система звичайних диференціальних рівнянь, цикл рендерингу на canvas, кілька повзунків. Ці п'ять забрали більше тижня кожна і змусили нас переосмислити весь підхід.

#1

Конструктор мостів (МСЕ)

Збирання глобальної матриці жорсткості з довільних балкових елементів, розв'язання розрідженої системи Ax = b методом Гаусса на JavaScript та візуалізація напружень кольором у реальному часі. Найскладніше — забезпечити, щоб граф топології лишався коректним, поки користувач перетягує вузли.

#2

Потік за методом ґратчастих рівнянь Больцмана

Забезпечення числової стабільності оператора зіткнень D2Q9 BGK при збереженні високих чисел Рейнольдса. Граничні умови Цзоу-Хе для швидкості на вході виявились несподівано нетривіальними, а крок «розповсюдження» вимагає кеш-дружнього розташування пам'яті — обмін двома плоскими масивами замість 3D-масиву.

#3

Акустика концертного залу (FDTD)

Запуск 2D акустичного розв'язувача методом кінцевих різниць у часовій області у воркер-потоці, потокова передача знімків поля тиску через SharedArrayBuffer та рендеринг фронту хвилі у вигляді кольорового градієнта на 60 FPS — при цьому потік інтерфейсу залишається повністю вільним.

#4

Згортання білка (метод Монте-Карло)

Згортання за HP-ґратковою моделлю методом імітаційного відпалу. Комбінаторний вибух конформацій вимагає ретельного графіка відпалу — надто швидке охолодження застрягає в локальних мінімумах, надто повільне — ніколи не сходиться в браузері.

#5

Симулятор квантових схем

Підтримка комплексного вектора стану розміром 2ⁿ у JavaScript-масиві Float64Array, застосування унітарних вентилів як матрично-векторних добутків та збереження чуйності інтерфейсу для до 10 кубітів (1024 амплітуди). Серіалізація вентилів у вигляді JSON-опису схеми була пізнім, але вирішальним архітектурним рішенням.

Архітектурні уроки

✅ Що спрацювало: один файл на симуляцію

Кожна симуляція — це один самодостатній HTML-файл. Жодного етапу збирання, жодних імпортів, жодного бандлера. Розгортання нової симуляції — це один git push. Читачі можуть переглянути вихідний код і зрозуміти все.

✅ Що спрацювало: спільне впровадження компонентів

Крихітний components.js впроваджує навігацію, футер і перемикач теми на кожну сторінку під час виконання. 300 файлів використовують одне визначення навігації. Ми змінювали навігацію тричі — щоразу це займало 30 секунд.

⚠️ Шкодуємо: копіювання CSS

Ранні симуляції мають власний фірмовий CSS. Пізніші симуляції використовують спільні змінні теми. Зараз у нас близько 50 симуляцій із незначними розбіжностями у розмірах шрифтів та відступах. Виправлення просте, але нудне.

⚠️ Шкодуємо: відсутність схеми даних симуляцій

simulations.json ріс органічно. У нас три різні конвенції для слагів категорій, дві — для тегів алгоритмів, і одна симуляція з опискою в ID, яка розповсюдилась усюди. Валідатор схеми з першого дня коштував би 30 хвилин.

Рішення, що змінило все: перенесення фізичних циклів у Web Workers. До воркерів будь-яка симуляція, що виконувала більше ~10 000 операцій на кадр, опускала інтерфейс нижче 60 FPS на мобільних пристроях. Потоки-воркери дозволяють фізиці працювати незалежно, передаючи позиції в основний потік через передавані ArrayBuffer. Основний потік лише рендерить.

Продуктивність: як ми досягли 60 FPS на мобільних пристроях

Кожна симуляція, що працює на 60 FPS на середньому Android-пристрої, має щонайменше три з цих п'яти властивостей:

Що далі: шлях до 500

Наступні 200 симуляцій зосередяться на напрямках, яким ми приділяли недостатньо уваги: біологічні системи (детальна геноміка, моделі нейронауки), передове матеріалознавство (молекулярна динаміка, спрощена ТФГ), геофізика (поширення сейсмічних хвиль, конвекція мантії з вищою роздільністю) та освітній/дитячий режим зі спрощеним керуванням і керованим відкриттям.

Ми також переносимо найважчі симуляції на обчислювальні шейдери WebGPU — розв'язувач методом ґратчастих рівнянь Больцмана, SPH-рідину та акустику FDTD. Обчислювальні шейдери працюють у 10–50 разів швидше за еквівалентний JavaScript-код, а це означає, що ми нарешті зможемо виконувати 3D CFD у реальному часі.