Babylon.js предоставляет мощный движок для работы с 3D-графикой в браузере, но при разработке сложных сцен возникает необходимость структурировать код, делать его модульным и легко тестируемым. Storybook-подход позволяет применять принципы компонентного дизайна из фронтенд-разработки к 3D-сценам, превращая отдельные объекты, материалы и эффекты в самостоятельные, повторно используемые компоненты.
Основной принцип — разделение сцены на компоненты:
Пример структуры файлов:
/scene
├─ /meshes
│ ├─ cube.js
│ └─ sphere.js
├─ /materials
│ ├─ standardMaterial.js
│ └─ pbrMaterial.js
├─ /lights
│ └─ directionalLight.js
├─ /camera
│ └─ arcRotateCamera.js
└─ scene.js
Каждый модуль экспортирует функцию, принимающую scene и конфигурацию, и возвращает созданный объект.
Меши оформляются как функции с возможностью переопределения параметров:
import { MeshBuilder, Vector3, StandardMaterial, Color3 } from "@babylonjs/core";
export function createCube(scene, { size = 1, position = new Vector3(0,0,0), color = Color3.Red() } = {}) {
const cube = MeshBuilder.CreateBox("cube", { size }, scene);
cube.position = position;
const material = new StandardMaterial("cubeMaterial", scene);
material.diffuseColor = color;
cube.material = material;
return cube;
}
Такой подход позволяет использовать один и тот же меш в разных контекстах сцены с разными параметрами.
Материалы и эффекты можно оформлять как отдельные компоненты, позволяющие быстро менять стиль объекта:
export function createGlassMaterial(scene, { alpha = 0.5, reflectionTexture = null } = {}) {
const material = new StandardMaterial("glassMaterial", scene);
material.alpha = alpha;
if (reflectionTexture) {
material.reflectionTexture = reflectionTexture;
}
material.specularPower = 64;
return material;
}
Это облегчает тестирование различных визуальных эффектов и упрощает интеграцию в Storybook, где каждый материал может быть отдельной историей.
Ключевой момент — выделение света и камеры в модули. Это упрощает создание шаблонных сцен и позволяет комбинировать разные источники света без изменения мешей.
import { ArcRotateCamera, Vector3, DirectionalLight } from "@babylonjs/core";
export function setupCamera(scene, { target = Vector3.Zero(), alpha = Math.PI/4, beta = Math.PI/3, radius = 10 } = {}) {
const camera = new ArcRotateCamera("camera", alpha, beta, radius, target, scene);
camera.attachControl(scene.getEngine().getRenderingCanvas(), true);
return camera;
}
export function createSunLight(scene, { direction = new Vector3(-1,-2,-1), intensity = 1 } = {}) {
const light = new DirectionalLight("sun", direction, scene);
light.intensity = intensity;
return light;
}
Такой подход облегчает экспериментирование с различными схемами освещения и ракурсами камеры в рамках одной сцены.
Каждый компонент сцены можно превратить в отдельную историю, аналогично Storybook для UI-компонентов:
Пример организации истории для меша:
import { createCube } from "../meshes/cube";
export default {
title: "Meshes/Cube",
argTypes: {
size: { control: 'number' },
color: { control: 'color' },
},
};
export const Default = (args) => {
const scene = new BABYLON.Scene(engine);
createCube(scene, args);
return scene;
};
Такой подход позволяет изолированно тестировать визуальные элементы, избегая необходимости запускать всю сцену целиком, и ускоряет итерации дизайна.
Компоненты объединяются в сцены через центральный модуль:
import { createCube } from "./meshes/cube";
import { setupCamera } from "./camera/arcRotateCamera";
import { createSunLight } from "./lights/directionalLight";
export function createScene(engine) {
const scene = new BABYLON.Scene(engine);
setupCamera(scene);
createSunLight(scene);
createCube(scene, { position: new BABYLON.Vector3(0, 0.5, 0) });
createCube(scene, { position: new BABYLON.Vector3(2, 0.5, 0), color: BABYLON.Color3.Blue() });
return scene;
}
Композиция строится на уровне чистых функций, что делает сцены предсказуемыми, легко тестируемыми и расширяемыми.
Storybook-подход в Babylon.js превращает 3D-сцену в набор чётко определённых, модульных компонентов. Меши, материалы, камеры и источники света становятся переиспользуемыми блоками, а визуальные эксперименты упрощаются благодаря изоляции и параметризации. Такой подход улучшает масштабируемость проектов, ускоряет процесс тестирования и повышает качество кода при работе с 3D-графикой в браузере.