assets/examples/README.md
# Babylon.js Real-World Examples
Comprehensive collection of production-ready Babylon.js patterns and implementations.
## Table of Contents
- [Model Loading & Optimization](#model-loading--optimization)
- [Advanced Materials](#advanced-materials)
- [Physics Simulations](#physics-simulations)
- [Particle Systems](#particle-systems)
- [Post-Processing Effects](#post-processing-effects)
- [GUI & User Interface](#gui--user-interface)
- [WebXR & VR](#webxr--vr)
- [Performance Optimization](#performance-optimization)
- [Camera Systems](#camera-systems)
- [Animation Patterns](#animation-patterns)
---
## Model Loading & Optimization
### GLTF Model Viewer with Progress
```javascript
import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader.js';
import { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial.js';
import '@babylonjs/loaders/glTF';
async function createModelViewer(scene, modelUrl, fileName) {
// Show loading progress
let loadingScreen = document.getElementById('loading');
BABYLON.SceneLoader.OnPluginActivatedObservable.addOnce((loader) => {
loader.onProgress = (event) => {
const progress = event.lengthComputable
? (event.loaded / event.total) * 100
: 0;
if (loadingScreen) {
loadingScreen.textContent = `Loading: ${progress.toFixed(0)}%`;
}
};
});
// Load model
const result = await SceneLoader.ImportMeshAsync(
null,
modelUrl,
fileName,
scene
);
if (loadingScreen) {
loadingScreen.style.display = 'none';
}
// Center model
const meshes = result.meshes;
const boundingBox = meshes[0].getHierarchyBoundingVectors();
const center = BABYLON.Vector3.Center(boundingBox.min, boundingBox.max);
meshes.forEach(mesh => {
mesh.position.subtractInPlace(center);
});
// Scale to fit
const size = boundingBox.max.subtract(boundingBox.min);
const maxDimension = Math.max(size.x, size.y, size.z);
const scale = 5 / maxDimension;
result.meshes[0].scaling.scaleInPlace(scale);
// Setup environment
const envTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(
'https://assets.babylonjs.com/environments/environmentSpecular.env',
scene
);
scene.environmentTexture = envTexture;
// Apply PBR to all meshes
meshes.forEach(mesh => {
if (mesh.material && mesh.material.albedoTexture) {
// Already has material, enhance it
mesh.material.environmentIntensity = 1.0;
} else if (!mesh.material) {
// No material, create default
const pbr = new PBRMaterial('defaultPBR', scene);
pbr.metallic = 0.0;
pbr.roughness = 0.5;
pbr.baseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
mesh.material = pbr;
}
});
return result;
}
```
### Optimized LOD (Level of Detail)
```javascript
async function createLODMesh(scene, highResUrl, medResUrl, lowResUrl) {
// Load all LOD levels
const highRes = await SceneLoader.ImportMeshAsync(null, '', highResUrl, scene);
const medRes = await SceneLoader.ImportMeshAsync(null, '', medResUrl, scene);
const lowRes = await SceneLoader.ImportMeshAsync(null, '', lowResUrl, scene);
const mainMesh = highRes.meshes[0];
const medMesh = medRes.meshes[0];
const lowMesh = lowRes.meshes[0];
// Add LOD levels
mainMesh.addLODLevel(15, medMesh); // Switch at 15 units
mainMesh.addLODLevel(30, lowMesh); // Switch at 30 units
mainMesh.addLODLevel(50, null); // Don't render beyond 50 units
return mainMesh;
}
```
### Mesh Simplification
```javascript
async function simplifyMesh(mesh, quality = 0.5) {
const simplified = await mesh.simplify(
[
{ quality: quality, distance: 10 },
{ quality: quality * 0.5, distance: 25 },
{ quality: quality * 0.25, distance: 50 }
],
true, // parallelProcessing
BABYLON.SimplificationType.QUADRATIC
);
return simplified;
}
```
### Batch Model Loading
```javascript
async function batchLoadModels(scene, models) {
const assetsManager = new BABYLON.AssetsManager(scene);
const loadedMeshes = [];
models.forEach((model, index) => {
const task = assetsManager.addMeshTask(
`model${index}`,
'',
model.path,
model.filename
);
task.onSuccess = (task) => {
task.loadedMeshes.forEach(mesh => {
mesh.position = model.position || BABYLON.Vector3.Zero();
mesh.scaling = model.scale || new BABYLON.Vector3(1, 1, 1);
});
loadedMeshes.push(...task.loadedMeshes);
};
task.onError = (task, message, exception) => {
console.error(`Failed to load ${model.filename}:`, message);
};
});
return new Promise((resolve) => {
assetsManager.onFinish = (tasks) => {
resolve(loadedMeshes);
};
assetsManager.load();
});
}
// Usage
const models = [
{ path: '/models/', filename: 'car.glb', position: new BABYLON.Vector3(0, 0, 0) },
{ path: '/models/', filename: 'tree.glb', position: new BABYLON.Vector3(5, 0, 0), scale: new BABYLON.Vector3(2, 2, 2) },
{ path: '/models/', filename: 'building.glb', position: new BABYLON.Vector3(-5, 0, 0) }
];
const meshes = await batchLoadModels(scene, models);
```
---
## Advanced Materials
### PBR Material with All Maps
```javascript
function createAdvancedPBRMaterial(scene) {
const pbr = new BABYLON.PBRMaterial('advancedPBR', scene);
// Base color
pbr.albedoTexture = new BABYLON.Texture('textures/albedo.png', scene);
// Metallic and roughness (combined in one texture)
pbr.metallicTexture = new BABYLON.Texture('textures/metallic_roughness.png', scene);
pbr.useRoughnessFromMetallicTextureAlpha = false;
pbr.useMetallnessFromMetallicTextureBlue = true;
// Normal map
pbr.bumpTexture = new BABYLON.Texture('textures/normal.png', scene);
pbr.invertNormalMapX = false;
pbr.invertNormalMapY = false;
// Ambient occlusion
pbr.ambientTexture = new BABYLON.Texture('textures/ao.png', scene);
pbr.useAmbientOcclusionFromMetallicTextureRed = true;
pbr.ambientTextureStrength = 1.0;
// Emissive
pbr.emissiveTexture = new BABYLON.Texture('textures/emissive.png', scene);
pbr.emissiveColor = new BABYLON.Color3(1, 1, 1);
pbr.emissiveIntensity = 1.0;
// Environment
pbr.environmentIntensity = 1.0;
pbr.reflectionTexture = scene.environmentTexture;
// Advanced settings
pbr.directIntensity = 1.0;
pbr.specularIntensity = 1.0;
pbr.usePhysicalLightFalloff = true;
pbr.useRadianceOverAlpha = true;
return pbr;
}
```
### Glass Material
```javascript
function createGlassMaterial(scene) {
const glass = new BABYLON.PBRMaterial('glass', scene);
glass.metallic = 0.0;
glass.roughness = 0.0;
glass.alpha = 0.3;
glass.alphaCutOff = 0.0;
glass.indexOfRefraction = 1.52; // Glass IOR
glass.reflectionTexture = scene.environmentTexture;
glass.refractionTexture = scene.environmentTexture;
glass.refractionTexture.refractionDepth = 0.8;
glass.linkRefractionWithTransparency = true;
glass.baseColor = new BABYLON.Color3(0.95, 0.95, 1.0);
glass.environmentIntensity = 1.0;
return glass;
}
```
### Water Material
```javascript
import { WaterMaterial } from '@babylonjs/materials/water/waterMaterial.js';
function createWaterMaterial(scene) {
const water = new WaterMaterial('water', scene, new BABYLON.Vector2(512, 512));
water.bumpTexture = new BABYLON.Texture('textures/waterbump.png', scene);
water.windForce = -5;
water.waveHeight = 0.3;
water.bumpHeight = 0.1;
water.windDirection = new BABYLON.Vector2(1, 1);
water.waterColor = new BABYLON.Color3(0.1, 0.3, 0.5);
water.colorBlendFactor = 0.3;
water.waveLength = 0.1;
// Add meshes to reflect/refract
water.addToRenderList(skybox);
water.addToRenderList(terrain);
water.addToRenderList(buildings);
return water;
}
```
### Node Material (Visual Shader)
```javascript
async function createNodeMaterial(scene) {
// Load from snippet
const nodeMaterial = await BABYLON.NodeMaterial.ParseFromSnippetAsync(
'#SNIPPET_ID',
scene
);
// Or create programmatically
const nodeMaterial2 = new BABYLON.NodeMaterial('node', scene);
// Input blocks
const position = new BABYLON.InputBlock('position');
position.setAsAttribute('position');
const worldPos = new BABYLON.TransformBlock('worldPos');
const worldViewProjection = new BABYLON.InputBlock('worldViewProjection');
worldViewProjection.setAsSystemValue(BABYLON.NodeMaterialSystemValues.WorldViewProjection);
const worldPosMult = new BABYLON.MultiplyBlock('worldPosMult');
worldPosMult.left.connectTo(worldViewProjection.output);
worldPosMult.right.connectTo(worldPos.output);
// Fragment output
const fragmentOutput = new BABYLON.FragmentOutputBlock('fragmentOutput');
const color = new BABYLON.ColorBlock('color');
color.value = new BABYLON.Color3(1, 0, 0);
fragmentOutput.rgb.connectTo(color.output);
nodeMaterial2.addOutputNode(fragmentOutput);
nodeMaterial2.build();
return nodeMaterial2;
}
```
### Dynamic Material Switching
```javascript
class MaterialSwitcher {
constructor(mesh, materials) {
this.mesh = mesh;
this.materials = materials;
this.currentIndex = 0;
}
switchMaterial() {
this.currentIndex = (this.currentIndex + 1) % this.materials.length;
this.mesh.material = this.materials[this.currentIndex];
}
setMaterial(index) {
if (index >= 0 && index < this.materials.length) {
this.currentIndex = index;
this.mesh.material = this.materials[index];
}
}
getCurrentMaterial() {
return this.materials[this.currentIndex];
}
}
// Usage
const materials = [
createPBRMaterial(scene),
createGlassMaterial(scene),
createMetallicMaterial(scene)
];
const switcher = new MaterialSwitcher(mesh, materials);
// Switch on click
scene.onPointerDown = () => {
switcher.switchMaterial();
};
```
---
## Physics Simulations
### Ragdoll Physics
```javascript
async function createRagdoll(scene, mesh) {
const havokInstance = await HavokPhysics();
const havokPlugin = new BABYLON.HavokPlugin(true, havokInstance);
scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), havokPlugin);
// Create physics bodies for each bone
const skeleton = mesh.skeleton;
const bonePhysics = [];
skeleton.bones.forEach((bone, index) => {
const boneMatrix = bone.getTransformNode();
if (boneMatrix) {
// Create capsule for bone
const capsule = BABYLON.MeshBuilder.CreateCapsule(
`bone_${index}`,
{
radius: 0.05,
height: 0.3
},
scene
);
capsule.position = boneMatrix.position.clone();
capsule.rotation = boneMatrix.rotation.clone();
// Add physics
const aggregate = new BABYLON.PhysicsAggregate(
capsule,
BABYLON.PhysicsShapeType.CAPSULE,
{ mass: 0.5, friction: 0.5 },
scene
);
bonePhysics.push({ bone, capsule, aggregate });
}
});
// Add constraints between bones
for (let i = 0; i < bonePhysics.length - 1; i++) {
const current = bonePhysics[i];
const next = bonePhysics[i + 1];
// Create joint
const constraint = new BABYLON.PhysicsConstraint(
BABYLON.PhysicsConstraintType.HINGE,
{
pivotA: new BABYLON.Vector3(0, 0.15, 0),
pivotB: new BABYLON.Vector3(0, -0.15, 0),
axisA: new BABYLON.Vector3(1, 0, 0),
axisB: new BABYLON.Vector3(1, 0, 0)
},
[
{ body: current.aggregate.body },
{ body: next.aggregate.body }
],
scene
);
}
return bonePhysics;
}
```
### Cloth Simulation
```javascript
function createCloth(scene, width = 10, height = 10, segments = 20) {
const cloth = BABYLON.MeshBuilder.CreateGround(
'cloth',
{ width, height, subdivisions: segments },
scene
);
// Make updatable
cloth.convertToFlatShadedMesh();
const positions = cloth.getVerticesData(BABYLON.VertexBuffer.PositionKind);
const indices = cloth.getIndices();
// Create particles for each vertex
const particles = [];
for (let i = 0; i < positions.length; i += 3) {
particles.push({
position: new BABYLON.Vector3(positions[i], positions[i + 1], positions[i + 2]),
previous: new BABYLON.Vector3(positions[i], positions[i + 1], positions[i + 2]),
pinned: positions[i + 1] >= height / 2 - 0.1 // Pin top row
});
}
// Update function
const gravity = new BABYLON.Vector3(0, -9.8, 0);
const damping = 0.99;
const timestep = 1 / 60;
scene.onBeforeRenderObservable.add(() => {
// Verlet integration
particles.forEach(particle => {
if (particle.pinned) return;
const velocity = particle.position.subtract(particle.previous);
particle.previous.copyFrom(particle.position);
const acceleration = gravity.scale(timestep * timestep);
particle.position.addInPlace(velocity.scale(damping)).addInPlace(acceleration);
});
// Constrain distances
for (let iteration = 0; iteration < 5; iteration++) {
for (let i = 0; i < indices.length; i += 3) {
const p1 = particles[indices[i]];
const p2 = particles[indices[i + 1]];
if (p1.pinned && p2.pinned) continue;
const diff = p1.position.subtract(p2.position);
const distance = diff.length();
const restDistance = width / segments;
const correction = diff.scale((distance - restDistance) / distance * 0.5);
if (!p1.pinned) p1.position.subtractInPlace(correction);
if (!p2.pinned) p2.position.addInPlace(correction);
}
}
// Update mesh
const newPositions = [];
particles.forEach(p => {
newPositions.push(p.position.x, p.position.y, p.position.z);
});
cloth.updateVerticesData(BABYLON.VertexBuffer.PositionKind, newPositions);
cloth.refreshBoundingInfo();
});
return cloth;
}
```
### Vehicle Physics
```javascript
class Vehicle {
constructor(scene, position) {
this.scene = scene;
// Create chassis
this.chassis = BABYLON.MeshBuilder.CreateBox(
'chassis',
{ width: 2, height: 0.5, depth: 4 },
scene
);
this.chassis.position = position;
const chassisAggregate = new BABYLON.PhysicsAggregate(
this.chassis,
BABYLON.PhysicsShapeType.BOX,
{ mass: 1000, friction: 0.5 },
scene
);
this.body = chassisAggregate.body;
// Create wheels
this.wheels = [];
const wheelPositions = [
new BABYLON.Vector3(-0.8, -0.5, 1.5), // Front left
new BABYLON.Vector3(0.8, -0.5, 1.5), // Front right
new BABYLON.Vector3(-0.8, -0.5, -1.5), // Rear left
new BABYLON.Vector3(0.8, -0.5, -1.5) // Rear right
];
wheelPositions.forEach((pos, index) => {
const wheel = BABYLON.MeshBuilder.CreateCylinder(
`wheel${index}`,
{ diameter: 0.8, height: 0.3, tessellation: 16 },
scene
);
wheel.rotation.z = Math.PI / 2;
wheel.parent = this.chassis;
wheel.position = pos;
this.wheels.push(wheel);
});
// Controls
this.throttle = 0;
this.steering = 0;
this.maxSpeed = 50;
this.acceleration = 10;
this.turnSpeed = 2;
this.setupControls();
}
setupControls() {
const keys = {};
window.addEventListener('keydown', (e) => {
keys[e.code] = true;
});
window.addEventListener('keyup', (e) => {
keys[e.code] = false;
});
this.scene.onBeforeRenderObservable.add(() => {
// Throttle
if (keys['KeyW']) {
this.throttle = Math.min(this.throttle + 0.1, 1);
} else if (keys['KeyS']) {
this.throttle = Math.max(this.throttle - 0.1, -0.5);
} else {
this.throttle *= 0.95; // Decay
}
// Steering
if (keys['KeyA']) {
this.steering = Math.max(this.steering - 0.1, -1);
} else if (keys['KeyD']) {
this.steering = Math.min(this.steering + 0.1, 1);
} else {
this.steering *= 0.9; // Center
}
// Apply forces
const forward = this.chassis.forward;
const force = forward.scale(this.throttle * this.acceleration * 1000);
this.body.applyForce(
force,
this.chassis.position
);
// Apply turning torque
const torque = new BABYLON.Vector3(0, this.steering * this.turnSpeed * 100, 0);
this.body.setAngularVelocity(torque);
// Rotate wheels
this.wheels.forEach((wheel, index) => {
wheel.rotation.x += this.throttle * 0.2;
// Steer front wheels
if (index < 2) {
wheel.rotation.y = this.steering * 0.5;
}
});
});
}
}
// Usage
const vehicle = new Vehicle(scene, new BABYLON.Vector3(0, 5, 0));
```
---
## Particle Systems
### Fire Effect
```javascript
function createFireEffect(scene, position) {
const fire = new BABYLON.ParticleSystem('fire', 2000, scene);
fire.particleTexture = new BABYLON.Texture(
'https://assets.babylonjs.com/textures/flare.png',
scene
);
fire.emitter = position;
fire.minEmitBox = new BABYLON.Vector3(-0.5, 0, -0.5);
fire.maxEmitBox = new BABYLON.Vector3(0.5, 0, 0.5);
// Colors
fire.color1 = new BABYLON.Color4(1, 0.5, 0, 1.0);
fire.color2 = new BABYLON.Color4(1, 0.2, 0, 1.0);
fire.colorDead = new BABYLON.Color4(0, 0, 0, 0.0);
// Size
fire.minSize = 0.3;
fire.maxSize = 1.0;
// Life time
fire.minLifeTime = 0.2;
fire.maxLifeTime = 0.4;
// Emission
fire.emitRate = 600;
// Blend mode
fire.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;
// Direction
fire.direction1 = new BABYLON.Vector3(-0.5, 4, -0.5);
fire.direction2 = new BABYLON.Vector3(0.5, 8, 0.5);
// Angular speed
fire.minAngularSpeed = 0;
fire.maxAngularSpeed = Math.PI;
// Speed
fire.minEmitPower = 1;
fire.maxEmitPower = 3;
fire.updateSpeed = 0.01;
// Gravity
fire.gravity = new BABYLON.Vector3(0, 0, 0);
fire.start();
return fire;
}
```
### Smoke Effect
```javascript
function createSmokeEffect(scene, position) {
const smoke = new BABYLON.ParticleSystem('smoke', 1000, scene);
smoke.particleTexture = new BABYLON.Texture(
'https://assets.babylonjs.com/textures/cloud.png',
scene
);
smoke.emitter = position;
smoke.minEmitBox = new BABYLON.Vector3(-0.3, 0, -0.3);
smoke.maxEmitBox = new BABYLON.Vector3(0.3, 0, 0.3);
// Colors - gray smoke
smoke.color1 = new BABYLON.Color4(0.3, 0.3, 0.3, 1.0);
smoke.color2 = new BABYLON.Color4(0.6, 0.6, 0.6, 1.0);
smoke.colorDead = new BABYLON.Color4(0, 0, 0, 0.0);
// Size - grows over time
smoke.minSize = 0.5;
smoke.maxSize = 1.5;
smoke.minScaleX = 0.5;
smoke.maxScaleX = 2.0;
smoke.minScaleY = 0.5;
smoke.maxScaleY = 2.0;
// Life time
smoke.minLifeTime = 2.0;
smoke.maxLifeTime = 4.0;
// Emission
smoke.emitRate = 200;
// Blend mode - additive for glow
smoke.blendMode = BABYLON.ParticleSystem.BLENDMODE_STANDARD;
// Direction - upwards
smoke.direction1 = new BABYLON.Vector3(-1, 3, -1);
smoke.direction2 = new BABYLON.Vector3(1, 5, 1);
// Speed
smoke.minEmitPower = 0.5;
smoke.maxEmitPower = 1.5;
// Gravity - slight upward float
smoke.gravity = new BABYLON.Vector3(0, -0.5, 0);
smoke.start();
return smoke;
}
```
### GPU Particle System (Performance)
```javascript
function createGPUParticles(scene, position) {
const gpu = new BABYLON.GPUParticleSystem('gpu', { capacity: 50000 }, scene);
gpu.particleTexture = new BABYLON.Texture(
'https://assets.babylonjs.com/textures/flare.png',
scene
);
gpu.emitter = position;
gpu.minEmitBox = new BABYLON.Vector3(-2, 0, -2);
gpu.maxEmitBox = new BABYLON.Vector3(2, 0, 2);
// Colors - rainbow
gpu.addColorGradient(0, new BABYLON.Color4(1, 0, 0, 1));
gpu.addColorGradient(0.3, new BABYLON.Color4(1, 1, 0, 1));
gpu.addColorGradient(0.6, new BABYLON.Color4(0, 1, 0, 1));
gpu.addColorGradient(1.0, new BABYLON.Color4(0, 0, 1, 0));
// Size over lifetime
gpu.addSizeGradient(0, 0.5);
gpu.addSizeGradient(0.5, 1.0);
gpu.addSizeGradient(1.0, 0.1);
// Life time
gpu.minLifeTime = 1.0;
gpu.maxLifeTime = 2.0;
// Emission
gpu.emitRate = 10000;
// Direction
gpu.direction1 = new BABYLON.Vector3(-1, 1, -1);
gpu.direction2 = new BABYLON.Vector3(1, 3, 1);
// Speed
gpu.minEmitPower = 2;
gpu.maxEmitPower = 4;
// Gravity
gpu.gravity = new BABYLON.Vector3(0, -9.8, 0);
gpu.start();
return gpu;
}
```
---
## Post-Processing Effects
### Bloom + DOF + Color Grading
```javascript
function createCinematicPipeline(scene, camera) {
const pipeline = new BABYLON.DefaultRenderingPipeline(
'cinematic',
true, // HDR
scene,
[camera]
);
// Enable features
pipeline.samples = 4; // MSAA
// FXAA anti-aliasing
pipeline.fxaaEnabled = true;
// Bloom
pipeline.bloomEnabled = true;
pipeline.bloomThreshold = 0.8;
pipeline.bloomWeight = 0.5;
pipeline.bloomKernel = 64;
pipeline.bloomScale = 0.5;
// Depth of field
pipeline.depthOfFieldEnabled = true;
pipeline.depthOfFieldBlurLevel = BABYLON.DepthOfFieldEffectBlurLevel.Medium;
pipeline.depthOfField.focusDistance = 5000;
pipeline.depthOfField.focalLength = 100;
pipeline.depthOfField.fStop = 2.0;
// Image processing
pipeline.imageProcessingEnabled = true;
// Tone mapping
pipeline.imageProcessing.toneMappingEnabled = true;
pipeline.imageProcessing.toneMappingType = BABYLON.ImageProcessingConfiguration.TONEMAPPING_ACES;
// Color grading
pipeline.imageProcessing.contrast = 1.2;
pipeline.imageProcessing.exposure = 1.0;
// Vignette
pipeline.imageProcessing.vignetteEnabled = true;
pipeline.imageProcessing.vignetteWeight = 2.0;
pipeline.imageProcessing.vignetteStretch = 0.5;
pipeline.imageProcessing.vignetteCameraFov = 0.8;
pipeline.imageProcessing.vignetteColor = new BABYLON.Color4(0, 0, 0, 0);
// Chromatic aberration
pipeline.chromaticAberrationEnabled = true;
pipeline.chromaticAberration.aberrationAmount = 30;
// Grain
pipeline.grainEnabled = true;
pipeline.grain.intensity = 10;
pipeline.grain.animated = true;
return pipeline;
}
```
### Outline/Glow Effect
```javascript
function createOutlineEffect(scene, meshes) {
const highlightLayer = new BABYLON.HighlightLayer('highlight', scene);
meshes.forEach(mesh => {
highlightLayer.addMesh(mesh, BABYLON.Color3.Green());
});
// Glow layer for emissive
const glowLayer = new BABYLON.GlowLayer('glow', scene);
glowLayer.intensity = 0.5;
return { highlightLayer, glowLayer };
}
```
### Custom Post-Process
```javascript
function createCustomPostProcess(camera) {
const postProcess = new BABYLON.PostProcess(
'customPP',
'./shaders/custom', // Path to shader files
['time'], // Uniforms
['textureSampler'], // Samplers
1.0, // Sampling ratio
camera
);
postProcess.onApply = (effect) => {
effect.setFloat('time', performance.now() / 1000);
};
return postProcess;
}
// Custom shader (shaders/custom.fragment.fx)
// precision highp float;
// uniform sampler2D textureSampler;
// uniform float time;
// varying vec2 vUV;
//
// void main(void) {
// vec2 uv = vUV;
// uv.x += sin(uv.y * 10.0 + time) * 0.01;
// gl_FragColor = texture2D(textureSampler, uv);
// }
```
---
## GUI & User Interface
### 3D Menu System
```javascript
import { AdvancedDynamicTexture } from '@babylonjs/gui/2D/advancedDynamicTexture.js';
import { StackPanel } from '@babylonjs/gui/2D/controls/stackPanel.js';
import { Button } from '@babylonjs/gui/2D/controls/button.js';
import { TextBlock } from '@babylonjs/gui/2D/controls/textBlock.js';
function create3DMenu(scene) {
// Create plane for menu
const plane = BABYLON.MeshBuilder.CreatePlane('menuPlane', { size: 4 }, scene);
plane.position = new BABYLON.Vector3(0, 2, 0);
// Create texture for plane
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(
plane,
1024,
1024
);
// Create panel
const panel = new BABYLON.GUI.StackPanel();
panel.width = '600px';
panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
panel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER;
advancedTexture.addControl(panel);
// Title
const title = new BABYLON.GUI.TextBlock();
title.text = 'Main Menu';
title.height = '80px';
title.color = 'white';
title.fontSize = 48;
title.fontWeight = 'bold';
panel.addControl(title);
// Buttons
const buttonData = [
{ text: 'Start Game', action: () => console.log('Start') },
{ text: 'Options', action: () => console.log('Options') },
{ text: 'Exit', action: () => console.log('Exit') }
];
buttonData.forEach(data => {
const button = BABYLON.GUI.Button.CreateSimpleButton('button', data.text);
button.width = '400px';
button.height = '60px';
button.color = 'white';
button.background = '#4fc3f7';
button.cornerRadius = 8;
button.thickness = 0;
button.fontSize = 24;
button.paddingTop = '10px';
button.paddingBottom = '10px';
button.onPointerEnterObservable.add(() => {
button.background = '#29b6f6';
});
button.onPointerOutObservable.add(() => {
button.background = '#4fc3f7';
});
button.onPointerUpObservable.add(data.action);
panel.addControl(button);
});
return { plane, advancedTexture };
}
```
### HUD with Stats
```javascript
function createHUD(scene, engine) {
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('HUD');
// FPS counter
const fpsText = new BABYLON.GUI.TextBlock();
fpsText.text = 'FPS: 60';
fpsText.color = 'white';
fpsText.fontSize = 18;
fpsText.textHorizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT;
fpsText.textVerticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
fpsText.paddingTop = '10px';
fpsText.paddingRight = '10px';
advancedTexture.addControl(fpsText);
// Health bar
const healthContainer = new BABYLON.GUI.Rectangle();
healthContainer.width = '200px';
healthContainer.height = '30px';
healthContainer.cornerRadius = 4;
healthContainer.color = 'white';
healthContainer.thickness = 2;
healthContainer.background = 'rgba(0, 0, 0, 0.5)';
healthContainer.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
healthContainer.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
healthContainer.left = 10;
healthContainer.top = 10;
advancedTexture.addControl(healthContainer);
const healthBar = new BABYLON.GUI.Rectangle();
healthBar.width = '100%';
healthBar.height = '100%';
healthBar.background = '#4caf50';
healthBar.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
healthContainer.addControl(healthBar);
// Update FPS
scene.onBeforeRenderObservable.add(() => {
fpsText.text = `FPS: ${engine.getFps().toFixed(0)}`;
});
return { advancedTexture, healthBar };
}
```
---
## WebXR & VR
### VR Scene Setup
```javascript
async function createVRScene(scene) {
// Create environment
const env = scene.createDefaultEnvironment({
createGround: true,
createSkybox: true
});
// Enable WebXR
const xrHelper = await scene.createDefaultXRExperienceAsync({
floorMeshes: [env.ground],
disableTeleportation: false
});
// Controller input
xrHelper.input.onControllerAddedObservable.add((controller) => {
controller.onMotionControllerInitObservable.add((motionController) => {
// Get components
const trigger = motionController.getMainComponent();
const squeeze = motionController.getComponent('squeeze');
const thumbstick = motionController.getComponent('thumbstick');
// Trigger press
trigger.onButtonStateChangedObservable.add((component) => {
if (component.pressed) {
console.log('Trigger pressed');
// Perform raycast
const ray = controller.getWorldPointerRayToRef(new BABYLON.Ray());
const hit = scene.pickWithRay(ray);
if (hit.pickedMesh) {
console.log('Hit:', hit.pickedMesh.name);
}
}
});
// Squeeze (grip) press
if (squeeze) {
squeeze.onButtonStateChangedObservable.add((component) => {
if (component.pressed) {
console.log('Grip pressed');
}
});
}
// Thumbstick
if (thumbstick) {
thumbstick.onAxisValueChangedObservable.add((axes) => {
console.log('Thumbstick:', axes.x, axes.y);
});
}
});
});
return xrHelper;
}
```
### VR Teleportation
```javascript
function setupVRTeleportation(xrHelper, validTargets) {
xrHelper.teleportation.addFloorMesh(validTargets[0]);
// Custom teleportation behavior
xrHelper.teleportation.onTargetMeshSelectedObservable.add((mesh) => {
console.log('Teleporting to:', mesh.name);
});
// Change teleportation arc color
xrHelper.teleportation.defaultTargetMeshOptions.teleportationFillColor = '#4fc3f7';
xrHelper.teleportation.defaultTargetMeshOptions.teleportationBorderColor = '#29b6f6';
}
```
---
## Performance Optimization
### Octree Scene Optimization
```javascript
function optimizeWithOctree(scene) {
const octree = scene.createOrUpdateSelectionOctree(32, 2);
// Enable octree for all meshes
scene.meshes.forEach(mesh => {
mesh.alwaysSelectAsActiveMesh = false;
});
return octree;
}
```
### Mesh Instancing
```javascript
function createInstancedMeshes(scene, template, count) {
const instances = [];
for (let i = 0; i < count; i++) {
const instance = template.createInstance(`instance${i}`);
instance.position = new BABYLON.Vector3(
Math.random() * 50 - 25,
0,
Math.random() * 50 - 25
);
instance.rotation.y = Math.random() * Math.PI * 2;
instances.push(instance);
}
return instances;
}
```
### Thin Instances (Best Performance)
```javascript
function createThinInstances(mesh, count) {
const matrices = [];
for (let i = 0; i < count; i++) {
const matrix = BABYLON.Matrix.Translation(
Math.random() * 50 - 25,
0,
Math.random() * 50 - 25
);
matrices.push(matrix);
}
const buffer = new Float32Array(matrices.length * 16);
matrices.forEach((matrix, index) => {
matrix.copyToArray(buffer, index * 16);
});
mesh.thinInstanceSetBuffer('matrix', buffer, 16);
}
```
This comprehensive examples documentation provides production-ready patterns for advanced Babylon.js development. Each example is complete and can be integrated into real projects.
assets/starter_babylon/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Babylon.js Starter</title>
<link rel="stylesheet" href="/src/style.css" />
</head>
<body>
<canvas id="renderCanvas"></canvas>
<div id="info">
<h1>Babylon.js Starter</h1>
<p>Interactive 3D scene with physics</p>
<ul>
<li><strong>Camera:</strong> Drag to rotate, scroll to zoom</li>
<li><strong>Click:</strong> Select meshes</li>
<li><strong>Space:</strong> Add sphere</li>
</ul>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
assets/starter_babylon/package.json
{
"name": "babylon-starter",
"private": true,
"version": "1.0.0",
"type": "module",
"description": "Babylon.js starter template with Vite",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@babylonjs/core": "^7.31.1",
"@babylonjs/loaders": "^7.31.1",
"@babylonjs/havok": "^1.3.8"
},
"devDependencies": {
"vite": "^5.0.11"
}
}
assets/starter_babylon/README.md
# Babylon.js Starter Template
Production-ready Babylon.js starter with Vite, physics, PBR materials, and interactive features.
## Features
- ⚡️ **Vite** - Fast build tool and dev server
- 🎮 **Babylon.js 7.x** - Latest version with WebGPU support
- 🎯 **Physics Engine** - Havok physics integration
- 🎨 **PBR Materials** - Physically based rendering
- 💡 **Dynamic Lighting** - Hemispheric + Directional with shadows
- 🖱️ **Interactive** - Mesh picking and keyboard controls
- 📊 **FPS Counter** - Performance monitoring
- 🐛 **Inspector** - Built-in debug tools (Shift+Ctrl+Alt+I)
## Quick Start
### Installation
```bash
npm install
# or
yarn
# or
pnpm install
```
### Development
```bash
npm run dev
```
Opens at `http://localhost:3000`
### Build
```bash
npm run build
```
### Preview Production Build
```bash
npm run preview
```
## Project Structure
```
starter_babylon/
├── index.html # Entry HTML
├── package.json # Dependencies
├── vite.config.js # Vite configuration
└── src/
├── main.js # Main application
└── style.css # Styles
```
## What's Included
### Scene Setup
- **Camera**: ArcRotateCamera with orbit controls
- **Lights**: Hemispheric ambient + Directional with shadows
- **Ground**: 20x20 plane with physics
- **Meshes**: PBR sphere, standard material box, metallic sphere
### Physics
- **Havok Physics Engine** integrated
- **Realistic gravity** (9.8 m/s²)
- **Collision detection** and response
- **Adjustable restitution** (bounciness)
### Materials
**PBR Material (Sphere 1)**
```javascript
const pbrMaterial = new PBRMaterial('pbrMat', scene);
pbrMaterial.metallic = 1.0;
pbrMaterial.roughness = 0.3;
pbrMaterial.baseColor = new Color3(0.9, 0.1, 0.1);
```
**Standard Material (Box)**
```javascript
const standardMaterial = new StandardMaterial('standardMat', scene);
standardMaterial.diffuseColor = new Color3(0.2, 0.8, 0.3);
standardMaterial.specularPower = 32;
```
### Interactions
- **Mouse Click**: Select and highlight meshes
- **Spacebar**: Add random spheres with physics
- **Camera Controls**: Drag to rotate, scroll to zoom
- **Inspector**: Shift+Ctrl+Alt+I to toggle debug layer
## Customization
### Change Camera
Replace ArcRotateCamera with FreeCamera for FPS-style:
```javascript
import { FreeCamera } from '@babylonjs/core/Cameras/freeCamera.js';
const camera = new FreeCamera('camera', new Vector3(0, 5, -10), scene);
camera.setTarget(Vector3.Zero());
camera.attachControl(canvas, true);
```
### Add More Lights
```javascript
import { PointLight } from '@babylonjs/core/Lights/pointLight.js';
const pointLight = new PointLight('pointLight', new Vector3(0, 10, 0), scene);
pointLight.intensity = 0.5;
pointLight.diffuse = new Color3(1, 0.5, 0);
```
### Load GLTF Models
```javascript
import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader.js';
import '@babylonjs/loaders/glTF';
const result = await SceneLoader.ImportMeshAsync(
null,
'https://assets.babylonjs.com/meshes/',
'village.glb',
scene
);
console.log('Loaded:', result.meshes);
```
### Add Post-Processing
```javascript
import { DefaultRenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.js';
const pipeline = new DefaultRenderingPipeline('pipeline', true, scene, [camera]);
pipeline.fxaaEnabled = true;
pipeline.samples = 4;
pipeline.bloomEnabled = true;
pipeline.bloomThreshold = 0.8;
pipeline.bloomWeight = 0.5;
```
### Create Custom Meshes
```javascript
import { CreateTorus } from '@babylonjs/core/Meshes/Builders/torusBuilder.js';
const torus = CreateTorus('torus', {
diameter: 3,
thickness: 1,
tessellation: 16
}, scene);
torus.position.y = 2;
```
### Add GUI
```javascript
import { AdvancedDynamicTexture } from '@babylonjs/gui/2D/advancedDynamicTexture.js';
import { Button } from '@babylonjs/gui/2D/controls/button.js';
const advancedTexture = AdvancedDynamicTexture.CreateFullscreenUI('UI');
const button = Button.CreateSimpleButton('button', 'Reset Scene');
button.width = '150px';
button.height = '40px';
button.color = 'white';
button.background = '#4fc3f7';
button.cornerRadius = 8;
button.onPointerUpObservable.add(() => {
console.log('Reset clicked');
});
advancedTexture.addControl(button);
```
## Performance Tips
1. **Use PBR Materials** - More realistic and efficient than standard materials
2. **Optimize Shadow Maps** - Reduce shadowGenerator size if needed
3. **Freeze World Matrices** - For static meshes: `mesh.freezeWorldMatrix()`
4. **Use Instances** - For repeated meshes: `mesh.createInstance('instance1')`
5. **Optimize Physics** - Set appropriate mass and restitution values
6. **Hardware Scaling** - Reduce resolution if FPS drops: `engine.setHardwareScalingLevel(2)`
## Debugging
### Inspector
Press **Shift+Ctrl+Alt+I** to toggle the Babylon.js Inspector:
- View scene graph
- Inspect mesh properties
- Debug materials
- Analyze performance
- Tweak values in real-time
### Console Logs
The template includes helpful console logs:
- Selected mesh names
- FPS display in top-right corner
### Common Issues
**Physics not working?**
- Ensure Havok is properly initialized with `await HavokPhysics()`
- Check that physics aggregates are created after `scene.enablePhysics()`
**Meshes not visible?**
- Check camera position and target
- Verify mesh positions
- Ensure materials are applied
**Performance issues?**
- Reduce shadow map size
- Disable post-processing
- Use hardware scaling
- Optimize mesh count
## Next Steps
### Add Animations
```javascript
import { Animation } from '@babylonjs/core/Animations/animation.js';
const animation = Animation.CreateAndStartAnimation(
'rotate',
mesh,
'rotation.y',
30,
120,
0,
Math.PI * 2,
Animation.ANIMATIONLOOPMODE_CYCLE
);
```
### Enable WebXR (VR/AR)
```javascript
const env = scene.createDefaultEnvironment();
const xr = await scene.createDefaultXRExperienceAsync({
floorMeshes: [env.ground]
});
```
### Add Particles
```javascript
import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem.js';
import { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
const particleSystem = new ParticleSystem('particles', 2000, scene);
particleSystem.particleTexture = new Texture('particle.png', scene);
particleSystem.emitter = new Vector3(0, 5, 0);
particleSystem.start();
```
## Resources
- [Babylon.js Documentation](https://doc.babylonjs.com/)
- [Babylon.js Playground](https://playground.babylonjs.com/)
- [Babylon.js Forum](https://forum.babylonjs.com/)
- [Babylon.js Examples](https://doc.babylonjs.com/examples/)
## License
MIT - Free for personal and commercial use
assets/starter_babylon/src/main.js
import { Engine } from '@babylonjs/core/Engines/engine.js';
import { Scene } from '@babylonjs/core/scene.js';
import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera.js';
import { Vector3, Color3, Color4 } from '@babylonjs/core/Maths/math.js';
import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight.js';
import { DirectionalLight } from '@babylonjs/core/Lights/directionalLight.js';
import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator.js';
import { CreateGround } from '@babylonjs/core/Meshes/Builders/groundBuilder.js';
import { CreateSphere } from '@babylonjs/core/Meshes/Builders/sphereBuilder.js';
import { CreateBox } from '@babylonjs/core/Meshes/Builders/boxBuilder.js';
import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial.js';
import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial.js';
import HavokPhysics from '@babylonjs/havok';
import { HavokPlugin } from '@babylonjs/core/Physics/v2/Plugins/havokPlugin.js';
import { PhysicsAggregate } from '@babylonjs/core/Physics/v2/physicsAggregate.js';
import { PhysicsShapeType } from '@babylonjs/core/Physics/v2/IPhysicsEnginePlugin.js';
// Import side effects for picking
import '@babylonjs/core/Culling/ray.js';
import '@babylonjs/core/Collisions/collisionCoordinator.js';
const canvas = document.getElementById('renderCanvas');
const engine = new Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true
});
const createScene = async function() {
const scene = new Scene(engine);
scene.clearColor = new Color4(0.1, 0.1, 0.15, 1.0);
// Camera
const camera = new ArcRotateCamera(
'camera',
-Math.PI / 2,
Math.PI / 3,
15,
Vector3.Zero(),
scene
);
camera.attachControl(canvas, true);
camera.lowerRadiusLimit = 5;
camera.upperRadiusLimit = 50;
camera.wheelPrecision = 50;
// Lights
const hemiLight = new HemisphericLight('hemiLight', new Vector3(0, 1, 0), scene);
hemiLight.intensity = 0.5;
const dirLight = new DirectionalLight('dirLight', new Vector3(-1, -2, -1), scene);
dirLight.position = new Vector3(20, 40, 20);
dirLight.intensity = 0.7;
// Shadows
const shadowGenerator = new ShadowGenerator(1024, dirLight);
shadowGenerator.useExponentialShadowMap = true;
// Ground
const ground = CreateGround('ground', { width: 20, height: 20 }, scene);
const groundMaterial = new StandardMaterial('groundMat', scene);
groundMaterial.diffuseColor = new Color3(0.3, 0.3, 0.35);
groundMaterial.specularColor = new Color3(0.1, 0.1, 0.1);
ground.material = groundMaterial;
ground.receiveShadows = true;
// Initialize physics
const havokInstance = await HavokPhysics();
const havokPlugin = new HavokPlugin(true, havokInstance);
scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin);
// Ground physics
const groundAggregate = new PhysicsAggregate(
ground,
PhysicsShapeType.BOX,
{ mass: 0 },
scene
);
// Create PBR sphere
const sphere1 = CreateSphere('sphere1', { diameter: 2 }, scene);
sphere1.position = new Vector3(-3, 3, 0);
const pbrMaterial = new PBRMaterial('pbrMat', scene);
pbrMaterial.metallic = 1.0;
pbrMaterial.roughness = 0.3;
pbrMaterial.baseColor = new Color3(0.9, 0.1, 0.1);
sphere1.material = pbrMaterial;
shadowGenerator.addShadowCaster(sphere1);
const sphere1Aggregate = new PhysicsAggregate(
sphere1,
PhysicsShapeType.SPHERE,
{ mass: 1, restitution: 0.8 },
scene
);
// Create standard material box
const box1 = CreateBox('box1', { size: 1.5 }, scene);
box1.position = new Vector3(3, 3, 0);
const standardMaterial = new StandardMaterial('standardMat', scene);
standardMaterial.diffuseColor = new Color3(0.2, 0.8, 0.3);
standardMaterial.specularColor = new Color3(0.5, 0.5, 0.5);
standardMaterial.specularPower = 32;
box1.material = standardMaterial;
shadowGenerator.addShadowCaster(box1);
const box1Aggregate = new PhysicsAggregate(
box1,
PhysicsShapeType.BOX,
{ mass: 1, restitution: 0.5 },
scene
);
// Create metallic sphere
const sphere2 = CreateSphere('sphere2', { diameter: 1.8 }, scene);
sphere2.position = new Vector3(0, 5, 2);
const metallicMaterial = new PBRMaterial('metallicMat', scene);
metallicMaterial.metallic = 0.9;
metallicMaterial.roughness = 0.1;
metallicMaterial.baseColor = new Color3(0.8, 0.8, 0.9);
sphere2.material = metallicMaterial;
shadowGenerator.addShadowCaster(sphere2);
const sphere2Aggregate = new PhysicsAggregate(
sphere2,
PhysicsShapeType.SPHERE,
{ mass: 1, restitution: 0.9 },
scene
);
// Picking
let selectedMesh = null;
scene.onPointerDown = function(evt, pickResult) {
if (pickResult.hit && pickResult.pickedMesh !== ground) {
// Deselect previous
if (selectedMesh && selectedMesh.material) {
selectedMesh.material.emissiveColor = new Color3(0, 0, 0);
}
// Select new
selectedMesh = pickResult.pickedMesh;
if (selectedMesh.material) {
selectedMesh.material.emissiveColor = new Color3(0.2, 0.2, 0);
}
console.log('Selected:', selectedMesh.name);
}
};
// Add sphere on spacebar
let sphereCount = 3;
window.addEventListener('keydown', (evt) => {
if (evt.code === 'Space') {
const newSphere = CreateSphere('sphere' + sphereCount, { diameter: 1.5 }, scene);
newSphere.position = new Vector3(
Math.random() * 6 - 3,
8,
Math.random() * 6 - 3
);
const randomMaterial = new PBRMaterial('mat' + sphereCount, scene);
randomMaterial.metallic = Math.random();
randomMaterial.roughness = Math.random() * 0.5 + 0.2;
randomMaterial.baseColor = new Color3(
Math.random(),
Math.random(),
Math.random()
);
newSphere.material = randomMaterial;
shadowGenerator.addShadowCaster(newSphere);
new PhysicsAggregate(
newSphere,
PhysicsShapeType.SPHERE,
{ mass: 1, restitution: 0.7 },
scene
);
sphereCount++;
}
});
// FPS counter
let fpsDisplay = document.createElement('div');
fpsDisplay.style.position = 'absolute';
fpsDisplay.style.top = '10px';
fpsDisplay.style.right = '10px';
fpsDisplay.style.color = 'white';
fpsDisplay.style.fontFamily = 'monospace';
fpsDisplay.style.fontSize = '14px';
fpsDisplay.style.background = 'rgba(0, 0, 0, 0.5)';
fpsDisplay.style.padding = '8px 12px';
fpsDisplay.style.borderRadius = '4px';
document.body.appendChild(fpsDisplay);
scene.onBeforeRenderObservable.add(() => {
fpsDisplay.textContent = `FPS: ${engine.getFps().toFixed(0)}`;
});
return scene;
};
// Create scene and start render loop
createScene().then(scene => {
engine.runRenderLoop(() => {
scene.render();
});
});
// Handle resize
window.addEventListener('resize', () => {
engine.resize();
});
// Optional: Debug layer (Shift+Ctrl+Alt+I)
window.addEventListener('keydown', (ev) => {
if (ev.shiftKey && ev.ctrlKey && ev.altKey && (ev.key === 'I' || ev.key === 'i')) {
import('@babylonjs/core/Debug/debugLayer.js').then(() => {
import('@babylonjs/inspector').then(() => {
if (engine.scenes[0].debugLayer.isVisible()) {
engine.scenes[0].debugLayer.hide();
} else {
engine.scenes[0].debugLayer.show();
}
});
});
}
});
assets/starter_babylon/src/style.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
}
#renderCanvas {
width: 100%;
height: 100%;
touch-action: none;
display: block;
}
#info {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(10px);
color: white;
padding: 20px 24px;
border-radius: 12px;
max-width: 300px;
font-size: 14px;
line-height: 1.6;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
#info h1 {
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
color: #fff;
}
#info p {
margin-bottom: 12px;
color: #ccc;
font-size: 13px;
}
#info ul {
list-style: none;
margin: 0;
padding: 0;
}
#info li {
margin: 6px 0;
color: #ddd;
font-size: 12px;
}
#info strong {
color: #4fc3f7;
font-weight: 600;
}
@media (max-width: 768px) {
#info {
bottom: 10px;
left: 10px;
right: 10px;
max-width: none;
padding: 16px 20px;
}
#info h1 {
font-size: 16px;
}
#info p {
font-size: 12px;
}
#info li {
font-size: 11px;
}
}
assets/starter_babylon/vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
server: {
port: 3000,
open: true
},
build: {
target: 'esnext',
minify: 'terser'
},
optimizeDeps: {
exclude: ['@babylonjs/havok']
}
});
references/api_reference.md
# Babylon.js API Reference
Complete API reference for Babylon.js 7.x covering core classes, methods, and properties.
## Table of Contents
- [Engine](#engine)
- [Scene](#scene)
- [Cameras](#cameras)
- [Lights](#lights)
- [Meshes](#meshes)
- [Materials](#materials)
- [Textures](#textures)
- [Physics](#physics)
- [Animations](#animations)
- [GUI](#gui)
- [Post-Processing](#post-processing)
---
## Engine
### BABYLON.Engine
Main rendering engine that manages the WebGL context and rendering loop.
#### Constructor
```typescript
new Engine(
canvasOrContext: HTMLCanvasElement | WebGLRenderingContext,
antialias?: boolean,
options?: EngineOptions,
adaptToDeviceRatio?: boolean
): Engine
```
**Parameters:**
- `canvasOrContext`: HTML canvas element or WebGL context
- `antialias`: Enable anti-aliasing (default: false)
- `options`: Engine configuration options
- `adaptToDeviceRatio`: Adapt to device pixel ratio (default: false)
**EngineOptions:**
```typescript
interface EngineOptions {
preserveDrawingBuffer?: boolean; // Keep buffer for screenshots
stencil?: boolean; // Enable stencil buffer
disableWebGL2Support?: boolean; // Force WebGL 1
powerPreference?: string; // "high-performance" | "low-power"
failIfMajorPerformanceCaveat?: boolean;
deterministicLockstep?: boolean; // Fixed timestep
lockstepMaxSteps?: number; // Max steps per frame
}
```
#### Properties
```typescript
engine.isFullscreen: boolean // Current fullscreen state
engine.isPointerLock: boolean // Pointer lock state
engine.scenes: Scene[] // All scenes
engine.renderEvenInBackground: boolean // Continue rendering when tab hidden
engine.enableOfflineSupport: boolean // Enable IndexedDB caching
engine.doNotHandleContextLost: boolean // Disable context lost recovery
```
#### Methods
**Rendering**
```typescript
engine.runRenderLoop(renderFunction: () => void): void
engine.stopRenderLoop(renderFunction?: () => void): void
engine.resize(forceResize?: boolean): void
engine.setHardwareScalingLevel(level: number): void // 1 = native, 2 = half resolution
engine.getHardwareScalingLevel(): number
engine.setSize(width: number, height: number, forceSetSize?: boolean): void
```
**Frame Info**
```typescript
engine.getFps(): number
engine.getDeltaTime(): number // Milliseconds since last frame
engine.getTimeStep(): number // Time step in ms
```
**State Management**
```typescript
engine.wipeCaches(bruteForce?: boolean): void
engine.dispose(): void
engine.clear(color: Color4, backBuffer: boolean, depth: boolean, stencil?: boolean): void
```
**Screenshots**
```typescript
engine.createScreenshot(
camera: Camera,
size: number | { width: number, height: number },
successCallback: (data: string) => void,
mimeType?: string,
forceDownload?: boolean
): void
engine.createScreenshotUsingRenderTarget(
camera: Camera,
size: number | { width: number, height: number },
successCallback: (data: string) => void,
mimeType?: string,
samples?: number,
antialiasing?: boolean,
fileName?: string
): void
```
---
## Scene
### BABYLON.Scene
Container for all 3D objects, cameras, lights, and materials.
#### Constructor
```typescript
new Scene(
engine: Engine,
options?: SceneOptions
): Scene
```
**SceneOptions:**
```typescript
interface SceneOptions {
useGeometryUniqueIdsMap?: boolean; // Faster geometry operations
useMaterialMeshMap?: boolean; // Faster material operations
useClonedMeshMap?: boolean; // Faster clone operations
virtual?: boolean; // Don't render automatically
}
```
#### Properties
**Core**
```typescript
scene.activeCamera: Camera | null // Current rendering camera
scene.activeCameras: Camera[] // For multi-viewport
scene.meshes: AbstractMesh[] // All meshes
scene.lights: Light[] // All lights
scene.cameras: Camera[] // All cameras
scene.materials: Material[] // All materials
scene.textures: BaseTexture[] // All textures
scene.transformNodes: TransformNode[] // Transform-only nodes
```
**Rendering**
```typescript
scene.autoClear: boolean // Auto-clear buffers
scene.autoClearDepthAndStencil: boolean // Auto-clear depth/stencil
scene.clearColor: Color4 // Background color
scene.ambientColor: Color3 // Ambient lighting color
scene.fogEnabled: boolean // Enable fog
scene.fogMode: number // Scene.FOGMODE_*
scene.fogDensity: number // Fog density
scene.fogStart: number // Linear fog start
scene.fogEnd: number // Linear fog end
scene.fogColor: Color3 // Fog color
```
**Optimization**
```typescript
scene.blockMaterialDirtyMechanism: boolean // Prevent material updates
scene.useDelayedTextureLoading: boolean // Lazy texture loading
scene.skipPointerMovePicking: boolean // Disable pointer move picking
scene.forceShowBoundingBoxes: boolean // Debug bounding boxes
scene.skipFrustumClipping: boolean // Disable frustum culling
```
**Animation**
```typescript
scene.animationsEnabled: boolean // Enable animations
scene.useConstantAnimationDeltaTime: boolean // Fixed timestep
scene.constantlyUpdateMeshUnderPointer: boolean // Continuous picking
```
#### Methods
**Rendering**
```typescript
scene.render(updateCameras?: boolean, ignoreAnimations?: boolean): void
scene.enableDepthRenderer(camera?: Camera, useFloat?: boolean): DepthRenderer
scene.enableGeometryBufferRenderer(ratio?: number): GeometryBufferRenderer
```
**Mesh Management**
```typescript
scene.getMeshByName(name: string): AbstractMesh | null
scene.getMeshById(id: string): AbstractMesh | null
scene.getMeshesByTags(tagsQuery: string): Mesh[]
scene.removeMesh(mesh: AbstractMesh): number
```
**Camera Management**
```typescript
scene.getCameraByName(name: string): Camera | null
scene.getCameraById(id: string): Camera | null
scene.removeCamera(camera: Camera): number
```
**Light Management**
```typescript
scene.getLightByName(name: string): Light | null
scene.getLightById(id: string): Light | null
scene.removeLight(light: Light): number
```
**Material Management**
```typescript
scene.getMaterialByName(name: string): Material | null
scene.getMaterialById(id: string): Material | null
scene.removeMaterial(material: Material): number
```
**Animation**
```typescript
scene.beginAnimation(
target: any,
from: number,
to: number,
loop?: boolean,
speedRatio?: number,
onAnimationEnd?: () => void,
animatable?: Animatable,
stopCurrent?: boolean,
targetMask?: (target: any) => boolean
): Animatable
scene.stopAnimation(target: any, animationName?: string): void
scene.stopAllAnimations(): void
scene.getAnimatableByTarget(target: any): Animatable | null
```
**Picking**
```typescript
scene.pick(
x: number,
y: number,
predicate?: (mesh: AbstractMesh) => boolean,
fastCheck?: boolean,
camera?: Camera
): PickingInfo
scene.pickWithRay(
ray: Ray,
predicate?: (mesh: AbstractMesh) => boolean,
fastCheck?: boolean
): PickingInfo
scene.multiPick(
x: number,
y: number,
predicate?: (mesh: AbstractMesh) => boolean,
camera?: Camera
): PickingInfo[]
```
**Environment**
```typescript
scene.createDefaultEnvironment(options?: IEnvironmentHelperOptions): EnvironmentHelper | null
scene.createDefaultCameraOrLight(
createArcRotateCamera?: boolean,
replace?: boolean,
attachCameraControls?: boolean
): void
scene.createDefaultSkybox(
environmentTexture?: BaseTexture,
pbr?: boolean,
scale?: number,
blur?: number,
setGlobalEnvTexture?: boolean
): Mesh | null
```
**Optimization**
```typescript
scene.createOrUpdateSelectionOctree(
maxCapacity?: number,
maxDepth?: number
): Octree<AbstractMesh>
scene.freezeActiveMeshes(frustumCullingEnabled?: boolean): Scene
scene.unfreezeActiveMeshes(): Scene
```
**Cleanup**
```typescript
scene.dispose(): void
scene.disposeSounds(): void
```
#### Events (Observables)
```typescript
scene.onBeforeRenderObservable: Observable<Scene>
scene.onAfterRenderObservable: Observable<Scene>
scene.onBeforeAnimationsObservable: Observable<Scene>
scene.onAfterAnimationsObservable: Observable<Scene>
scene.onBeforePhysicsObservable: Observable<Scene>
scene.onAfterPhysicsObservable: Observable<Scene>
scene.onBeforeCameraRenderObservable: Observable<Camera>
scene.onAfterCameraRenderObservable: Observable<Camera>
scene.onReadyObservable: Observable<Scene>
scene.onDataLoadedObservable: Observable<Scene>
scene.onDispose: () => void
scene.onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void
scene.onPointerUp: (evt: PointerEvent, pickInfo: PickingInfo) => void
scene.onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo) => void
scene.onPointerPick: (evt: PointerEvent, pickInfo: PickingInfo) => void
```
---
## Cameras
### Base Camera Properties
```typescript
camera.position: Vector3 // Camera position
camera.rotation: Vector3 // Camera rotation (Euler)
camera.fov: number // Field of view (radians)
camera.minZ: number // Near clipping plane
camera.maxZ: number // Far clipping plane
camera.inertia: number // Movement smoothing (0-1)
camera.speed: number // Movement speed
camera.angularSensibility: number // Mouse sensitivity
camera.layerMask: number // Rendering layers
camera.fovMode: number // Camera.FOVMODE_*
```
### BABYLON.FreeCamera
First-person camera with WASD controls.
```typescript
new FreeCamera(
name: string,
position: Vector3,
scene: Scene
): FreeCamera
```
**Properties:**
```typescript
camera.ellipsoid: Vector3 // Collision ellipsoid
camera.checkCollisions: boolean // Enable collisions
camera.applyGravity: boolean // Enable gravity
camera.keysUp: number[] // Key codes for forward
camera.keysDown: number[] // Key codes for backward
camera.keysLeft: number[] // Key codes for left
camera.keysRight: number[] // Key codes for right
camera.keysUpward: number[] // Key codes for up (fly mode)
camera.keysDownward: number[] // Key codes for down (fly mode)
```
**Methods:**
```typescript
camera.attachControl(noPreventDefault?: boolean): void
camera.detachControl(): void
camera.setTarget(target: Vector3): void
```
### BABYLON.ArcRotateCamera
Orbital camera that rotates around a target.
```typescript
new ArcRotateCamera(
name: string,
alpha: number, // Horizontal rotation (radians)
beta: number, // Vertical rotation (radians)
radius: number, // Distance from target
target: Vector3, // Look-at point
scene: Scene
): ArcRotateCamera
```
**Properties:**
```typescript
camera.alpha: number // Horizontal angle
camera.beta: number // Vertical angle
camera.radius: number // Distance
camera.target: Vector3 // Target position
camera.inertialAlphaOffset: number // Horizontal momentum
camera.inertialBetaOffset: number // Vertical momentum
camera.inertialRadiusOffset: number // Zoom momentum
camera.lowerAlphaLimit: number | null // Min horizontal
camera.upperAlphaLimit: number | null // Max horizontal
camera.lowerBetaLimit: number // Min vertical (0.01)
camera.upperBetaLimit: number // Max vertical (Math.PI - 0.01)
camera.lowerRadiusLimit: number | null // Min distance
camera.upperRadiusLimit: number | null // Max distance
camera.panningAxis: Vector3 // Panning direction
camera.panningInertia: number // Panning smoothing
camera.zoomOnFactor: number // Zoom speed
camera.wheelPrecision: number // Wheel sensitivity
camera.panningSensibility: number // Pan sensitivity
```
**Methods:**
```typescript
camera.setPosition(position: Vector3): void
camera.setTarget(target: Vector3): void
camera.focusOn(meshesOrMinMaxVectorAndDistance: any, doNotUpdateMaxZ?: boolean): void
camera.zoomOn(meshes?: AbstractMesh[], doNotUpdateMaxZ?: boolean): void
```
### BABYLON.UniversalCamera
Combination of FreeCamera and TouchCamera.
```typescript
new UniversalCamera(
name: string,
position: Vector3,
scene: Scene
): UniversalCamera
```
Inherits all FreeCamera properties and adds touch support.
### BABYLON.FollowCamera
Camera that follows a target mesh.
```typescript
new FollowCamera(
name: string,
position: Vector3,
scene: Scene
): FollowCamera
```
**Properties:**
```typescript
camera.lockedTarget: AbstractMesh // Mesh to follow
camera.radius: number // Distance from target
camera.heightOffset: number // Height above target
camera.rotationOffset: number // Horizontal offset
camera.cameraAcceleration: number // Movement speed
camera.maxCameraSpeed: number // Max speed
```
---
## Lights
### Base Light Properties
```typescript
light.diffuse: Color3 // Diffuse color
light.specular: Color3 // Specular color
light.intensity: number // Light intensity (0-1)
light.range: number // Effective range
light.includeOnlyMeshes: AbstractMesh[] // Only affect these
light.includedOnlyMeshes: AbstractMesh[] // Same as above
light.excludedMeshes: AbstractMesh[] // Don't affect these
light.excludeWithLayerMask: number // Layer mask exclusion
light.includeOnlyWithLayerMask: number // Layer mask inclusion
light.lightmapMode: number // Light.LIGHTMAP_*
```
### BABYLON.HemisphericLight
Ambient light with ground color.
```typescript
new HemisphericLight(
name: string,
direction: Vector3,
scene: Scene
): HemisphericLight
```
**Properties:**
```typescript
light.groundColor: Color3 // Color from below
light.direction: Vector3 // Light direction
```
### BABYLON.DirectionalLight
Parallel light (sun-like).
```typescript
new DirectionalLight(
name: string,
direction: Vector3,
scene: Scene
): DirectionalLight
```
**Properties:**
```typescript
light.direction: Vector3 // Light direction
light.position: Vector3 // For shadow calculation
light.shadowMinZ: number // Shadow near plane
light.shadowMaxZ: number // Shadow far plane
light.autoUpdateExtends: boolean // Auto-calculate shadow bounds
light.autoCalcShadowZBounds: boolean // Auto Z bounds
light.orthoLeft: number // Orthographic left
light.orthoRight: number // Orthographic right
light.orthoTop: number // Orthographic top
light.orthoBottom: number // Orthographic bottom
```
### BABYLON.PointLight
Omni-directional point light.
```typescript
new PointLight(
name: string,
position: Vector3,
scene: Scene
): PointLight
```
**Properties:**
```typescript
light.position: Vector3 // Light position
light.shadowMinZ: number // Shadow near plane
light.shadowMaxZ: number // Shadow far plane
```
### BABYLON.SpotLight
Focused cone light.
```typescript
new SpotLight(
name: string,
position: Vector3,
direction: Vector3,
angle: number,
exponent: number,
scene: Scene
): SpotLight
```
**Properties:**
```typescript
light.position: Vector3 // Light position
light.direction: Vector3 // Light direction
light.angle: number // Cone angle (radians)
light.exponent: number // Light falloff
light.shadowAngleScale: number // Shadow angle scale
light.innerAngle: number // Inner cone angle
```
---
## Meshes
### BABYLON.Mesh
Basic 3D mesh object.
#### Constructor
```typescript
new Mesh(
name: string,
scene: Scene | null,
parent?: Node,
source?: Mesh,
doNotCloneChildren?: boolean,
clonePhysicsImpostor?: boolean
): Mesh
```
#### Properties
**Transform**
```typescript
mesh.position: Vector3 // World position
mesh.rotation: Vector3 // Euler rotation
mesh.rotationQuaternion: Quaternion | null // Quaternion rotation
mesh.scaling: Vector3 // Scale factors
mesh.parent: Node | null // Parent node
mesh.billboardMode: number // Mesh.BILLBOARDMODE_*
```
**Visibility**
```typescript
mesh.isVisible: boolean // Render visibility
mesh.visibility: number // Transparency (0-1)
mesh.alphaIndex: number // Render order
mesh.infiniteDistance: boolean // Always render at distance
mesh.isPickable: boolean // Can be picked
mesh.showBoundingBox: boolean // Debug bounds
```
**Rendering**
```typescript
mesh.material: Material | null // Applied material
mesh.receiveShadows: boolean // Receive shadows
mesh.renderingGroupId: number // Rendering order group
mesh.layerMask: number // Camera layer mask
mesh.alwaysSelectAsActiveMesh: boolean // Skip frustum culling
mesh.doNotSyncBoundingInfo: boolean // Skip bounds sync
mesh.isOccluded: boolean // Occlusion query result
mesh.isOcclusionQueryInProgress: boolean // Query in progress
```
**Collisions**
```typescript
mesh.checkCollisions: boolean // Enable collision detection
mesh.ellipsoid: Vector3 // Collision shape
mesh.ellipsoidOffset: Vector3 // Collision offset
```
**LOD**
```typescript
mesh.useLODScreenCoverage: boolean // Use screen coverage for LOD
```
#### Methods
**Transform**
```typescript
mesh.setAbsolutePosition(absolutePosition: Vector3): Mesh
mesh.getAbsolutePosition(): Vector3
mesh.setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix?: boolean): Mesh
mesh.getPivotMatrix(): Matrix
mesh.setPreTransformMatrix(matrix: Matrix): Mesh
mesh.lookAt(targetPoint: Vector3, yawCor?: number, pitchCor?: number, rollCor?: number): Mesh
mesh.translate(axis: Vector3, distance: number, space?: Space): Mesh
mesh.rotate(axis: Vector3, amount: number, space?: Space): Mesh
mesh.rotateAround(point: Vector3, axis: Vector3, amount: number): Mesh
```
**Geometry**
```typescript
mesh.getBoundingInfo(): BoundingInfo
mesh.refreshBoundingInfo(applySkeleton?: boolean): Mesh
mesh.updateVerticesData(kind: string, data: FloatArray, updateExtends?: boolean, makeItUnique?: boolean): Mesh
mesh.getVerticesData(kind: string, copyWhenShared?: boolean, forceCopy?: boolean): FloatArray | null
mesh.getIndices(copyWhenShared?: boolean, forceCopy?: boolean): IndicesArray | null
mesh.getTotalVertices(): number
mesh.getTotalIndices(): number
```
**Cloning**
```typescript
mesh.clone(name: string, newParent?: Node | null, doNotCloneChildren?: boolean): Mesh
mesh.createInstance(name: string): InstancedMesh
```
**LOD**
```typescript
mesh.addLODLevel(distanceOrScreenCoverage: number, mesh: Mesh | null): Mesh
mesh.removeLODLevel(mesh: Mesh): Mesh
mesh.getLODLevelAtDistance(distance: number): Mesh | null
```
**Optimization**
```typescript
mesh.convertToFlatShadedMesh(): Mesh
mesh.convertToUnIndexedMesh(): Mesh
mesh.flipFaces(flipNormals?: boolean): Mesh
mesh.increaseVertices(numberPerEdge: number): void
mesh.forceSharedVertices(): void
mesh.freezeWorldMatrix(newWorldMatrix?: Matrix | null, stopRecursion?: boolean): Mesh
mesh.unfreezeWorldMatrix(): Mesh
```
**Disposal**
```typescript
mesh.dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void
```
### MeshBuilder
Static class for creating built-in shapes.
```typescript
// Box
BABYLON.MeshBuilder.CreateBox(name: string, options: {
size?: number;
width?: number;
height?: number;
depth?: number;
faceUV?: Vector4[];
faceColors?: Color4[];
sideOrientation?: number;
frontUVs?: Vector4;
backUVs?: Vector4;
wrap?: boolean;
topBaseAt?: number;
bottomBaseAt?: number;
updatable?: boolean;
}, scene?: Scene): Mesh
// Sphere
BABYLON.MeshBuilder.CreateSphere(name: string, options: {
segments?: number;
diameter?: number;
diameterX?: number;
diameterY?: number;
diameterZ?: number;
arc?: number;
slice?: number;
sideOrientation?: number;
frontUVs?: Vector4;
backUVs?: Vector4;
updatable?: boolean;
}, scene?: Scene): Mesh
// Cylinder
BABYLON.MeshBuilder.CreateCylinder(name: string, options: {
height?: number;
diameterTop?: number;
diameterBottom?: number;
diameter?: number;
tessellation?: number;
subdivisions?: number;
arc?: number;
faceColors?: Color4[];
faceUV?: Vector4[];
hasRings?: boolean;
enclose?: boolean;
cap?: number;
sideOrientation?: number;
frontUVs?: Vector4;
backUVs?: Vector4;
updatable?: boolean;
}, scene?: Scene): Mesh
// Plane
BABYLON.MeshBuilder.CreatePlane(name: string, options: {
size?: number;
width?: number;
height?: number;
sideOrientation?: number;
frontUVs?: Vector4;
backUVs?: Vector4;
updatable?: boolean;
sourcePlane?: Plane;
}, scene?: Scene): Mesh
// Ground
BABYLON.MeshBuilder.CreateGround(name: string, options: {
width?: number;
height?: number;
subdivisions?: number;
subdivisionsX?: number;
subdivisionsY?: number;
updatable?: boolean;
}, scene?: Scene): Mesh
// Ground from heightmap
BABYLON.MeshBuilder.CreateGroundFromHeightMap(name: string, url: string, options: {
width?: number;
height?: number;
subdivisions?: number;
minHeight?: number;
maxHeight?: number;
colorFilter?: Color3;
alphaFilter?: number;
updatable?: boolean;
onReady?: (mesh: GroundMesh) => void;
}, scene?: Scene): GroundMesh
// Torus
BABYLON.MeshBuilder.CreateTorus(name: string, options: {
diameter?: number;
thickness?: number;
tessellation?: number;
sideOrientation?: number;
frontUVs?: Vector4;
backUVs?: Vector4;
updatable?: boolean;
}, scene?: Scene): Mesh
// Lines
BABYLON.MeshBuilder.CreateLines(name: string, options: {
points: Vector3[];
updatable?: boolean;
instance?: LinesMesh;
colors?: Color4[];
useVertexAlpha?: boolean;
}, scene?: Scene): LinesMesh
// Ribbon
BABYLON.MeshBuilder.CreateRibbon(name: string, options: {
pathArray: Vector3[][];
closeArray?: boolean;
closePath?: boolean;
offset?: number;
updatable?: boolean;
sideOrientation?: number;
frontUVs?: Vector4;
backUVs?: Vector4;
instance?: Mesh;
invertUV?: boolean;
uvs?: Vector2[];
colors?: Color4[];
}, scene?: Scene): Mesh
```
---
## Materials
### BABYLON.StandardMaterial
Basic Phong-based material.
#### Constructor
```typescript
new StandardMaterial(
name: string,
scene: Scene
): StandardMaterial
```
#### Properties
**Colors**
```typescript
material.diffuseColor: Color3 // Main color
material.specularColor: Color3 // Highlight color
material.emissiveColor: Color3 // Self-illumination
material.ambientColor: Color3 // Ambient contribution
material.specularPower: number // Shininess (1-128)
```
**Textures**
```typescript
material.diffuseTexture: BaseTexture | null // Albedo map
material.ambientTexture: BaseTexture | null // Ambient occlusion
material.opacityTexture: BaseTexture | null // Transparency map
material.reflectionTexture: BaseTexture | null // Environment/reflection
material.emissiveTexture: BaseTexture | null // Emission map
material.specularTexture: BaseTexture | null // Specular map
material.bumpTexture: BaseTexture | null // Normal/bump map
material.lightmapTexture: BaseTexture | null // Baked lighting
material.refractionTexture: BaseTexture | null // Refraction map
```
**Rendering**
```typescript
material.alpha: number // Opacity (0-1)
material.backFaceCulling: boolean // Cull back faces
material.cullBackFaces: boolean // Same as above
material.sideOrientation: number // Material.SIDE_*
material.alphaMode: number // Material.ALPHA_*
material.transparencyMode: number | null // Material.MATERIAL_*
material.wireframe: boolean // Render as wireframe
material.pointsCloud: boolean // Render as points
material.fillMode: number // Material.FILLMODE_*
```
**Lighting**
```typescript
material.useEmissiveAsIllumination: boolean // Emissive as light
material.linkEmissiveWithDiffuse: boolean // Tie colors
material.useSpecularOverAlpha: boolean // Spec on transparent
material.useReflectionOverAlpha: boolean // Refl on transparent
material.useAlphaFromDiffuseTexture: boolean // Alpha from diffuse
material.useParallax: boolean // Parallax mapping
material.useParallaxOcclusion: boolean // Parallax occlusion
material.parallaxScaleBias: number // Parallax strength
material.roughness: number // Surface roughness
material.useLightmapAsShadowmap: boolean // Lightmap = shadows
material.useGlossinessFromSpecularMapAlpha: boolean // Glossiness source
```
**Fresnel**
```typescript
material.diffuseFresnelParameters: FresnelParameters | null
material.opacityFresnelParameters: FresnelParameters | null
material.reflectionFresnelParameters: FresnelParameters | null
material.emissiveFresnelParameters: FresnelParameters | null
material.refractionFresnelParameters: FresnelParameters | null
```
#### Methods
```typescript
material.clone(name: string): StandardMaterial
material.dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void
material.freeze(): void
material.unfreeze(): void
material.needAlphaBlending(): boolean
material.needAlphaTesting(): boolean
```
### BABYLON.PBRMaterial
Physically based rendering material.
#### Constructor
```typescript
new PBRMaterial(
name: string,
scene: Scene
): PBRMaterial
```
#### Properties
**Metallic-Roughness Workflow**
```typescript
material.metallic: number | null // Metalness (0-1)
material.roughness: number | null // Roughness (0-1)
material.metallicTexture: BaseTexture | null // Metallic map
material.roughnessTexture: BaseTexture | null // Roughness map (if separate)
material.metallicRoughnessTexture: BaseTexture | null // Combined MR map
material.baseColor: Color3 // Base color
material.baseTexture: BaseTexture | null // Base color map
material.albedoColor: Color3 // Same as baseColor
material.albedoTexture: BaseTexture | null // Same as baseTexture
```
**Specular-Glossiness Workflow**
```typescript
material.reflectivityColor: Color3 // Specular color
material.reflectivityTexture: BaseTexture | null // Specular map
material.microSurface: number // Glossiness (0-1)
material.microSurfaceTexture: BaseTexture | null // Glossiness map
material.useMicroSurfaceFromReflectivityMapAlpha: boolean
```
**Other Maps**
```typescript
material.bumpTexture: BaseTexture | null // Normal map
material.ambientTexture: BaseTexture | null // Ambient occlusion
material.ambientTextureStrength: number // AO strength
material.emissiveTexture: BaseTexture | null // Emission map
material.emissiveColor: Color3 // Emission color
material.emissiveIntensity: number // Emission strength
material.lightmapTexture: BaseTexture | null // Lightmap
material.opacityTexture: BaseTexture | null // Opacity map
```
**Environment**
```typescript
material.environmentTexture: BaseTexture | null // IBL/reflection
material.environmentIntensity: number // Environment strength
material.useRadianceOverAlpha: boolean // Refl over alpha
material.useSpecularOverAlpha: boolean // Spec over alpha
```
**Rendering**
```typescript
material.alpha: number // Opacity (0-1)
material.transparencyMode: number | null // PBRMaterial.PBRMATERIAL_*
material.alphaCutOff: number // Alpha test threshold
material.directIntensity: number // Direct light multiplier
material.emissiveIntensity: number // Emissive multiplier
material.environmentIntensity: number // Environment multiplier
material.specularIntensity: number // Specular multiplier
material.disableLighting: boolean // Unlit mode
material.unlit: boolean // Same as above
```
**Advanced**
```typescript
material.usePhysicalLightFalloff: boolean // Inverse square falloff
material.useRadianceOcclusion: boolean // Radiance AO
material.useHorizonOcclusion: boolean // Horizon AO
material.useAlphaFromAlbedoTexture: boolean // Alpha from albedo
material.forceIrradianceInFragment: boolean // Force fragment irradiance
material.realTimeFiltering: boolean // Real-time filtering
material.realTimeFilteringQuality: number // Filtering quality
```
---
## Textures
### BABYLON.Texture
2D texture from image file.
#### Constructor
```typescript
new Texture(
url: string | null,
sceneOrEngine: Scene | ThinEngine,
noMipmap?: boolean,
invertY?: boolean,
samplingMode?: number,
onLoad?: (() => void) | null,
onError?: ((message?: string, exception?: any) => void) | null,
buffer?: string | ArrayBuffer | ArrayBufferView | HTMLImageElement | Blob | ImageBitmap | null,
deleteBuffer?: boolean,
format?: number,
mimeType?: string
): Texture
```
#### Properties
```typescript
texture.url: string | null // Texture URL
texture.uOffset: number // U offset
texture.vOffset: number // V offset
texture.uScale: number // U scale
texture.vScale: number // V scale
texture.uAng: number // U rotation
texture.vAng: number // V rotation
texture.wAng: number // W rotation
texture.wrapU: number // Texture.WRAP_*
texture.wrapV: number // Texture.WRAP_*
texture.coordinatesMode: number // Texture.MODE_*
texture.coordinatesIndex: number // UV channel
texture.level: number // Texture level
texture.hasAlpha: boolean // Has alpha channel
texture.getAlphaFromRGB: boolean // Alpha from luminance
texture.invertZ: boolean // Invert Z (for normal maps)
texture.isBlocking: boolean // Block until loaded
```
#### Methods
```typescript
texture.clone(): Texture
texture.dispose(): void
texture.updateURL(url: string, buffer?: string | ArrayBuffer | ArrayBufferView | HTMLImageElement | Blob, onLoad?: () => void): void
texture.updateSamplingMode(samplingMode: number): void
```
### BABYLON.CubeTexture
Cubemap texture for reflections/environment.
```typescript
new CubeTexture(
rootUrl: string,
sceneOrEngine: Scene | ThinEngine,
extensions?: string[] | null,
noMipmap?: boolean,
files?: string[] | null,
onLoad?: (() => void) | null,
onError?: ((message?: string, exception?: any) => void) | null,
format?: number,
prefiltered?: boolean,
forcedExtension?: string | null
): CubeTexture
// Create from prefiltered DDS
CubeTexture.CreateFromPrefilteredData(url: string, scene: Scene, forcedExtension?: string): CubeTexture
```
### BABYLON.RenderTargetTexture
Render-to-texture for effects.
```typescript
new RenderTargetTexture(
name: string,
size: number | { width: number, height: number } | { ratio: number },
scene?: Scene,
generateMipMaps?: boolean,
doNotChangeAspectRatio?: boolean,
type?: number,
isCube?: boolean,
samplingMode?: number,
generateDepthBuffer?: boolean,
generateStencilBuffer?: boolean,
isMulti?: boolean,
format?: number,
delayAllocation?: boolean
): RenderTargetTexture
```
**Properties:**
```typescript
renderTarget.renderList: AbstractMesh[] | null // Meshes to render
renderTarget.activeCamera: Camera | null // Render camera
renderTarget.refreshRate: number // Update frequency
renderTarget.clearColor: Color4 // Clear color
```
---
## Physics
### Physics Engine Setup
```typescript
// Enable physics
scene.enablePhysics(
gravity?: Vector3,
plugin?: IPhysicsEnginePlugin
): boolean
// Default gravity
const gravity = new BABYLON.Vector3(0, -9.8, 0);
// Havok plugin
const havokInstance = await HavokPhysics();
const havokPlugin = new BABYLON.HavokPlugin(true, havokInstance);
scene.enablePhysics(gravity, havokPlugin);
```
### BABYLON.PhysicsAggregate
Physics body for a mesh (Havok v2).
```typescript
new PhysicsAggregate(
transformNode: TransformNode,
type: PhysicsShapeType,
options?: PhysicsAggregateParameters,
scene?: Scene
): PhysicsAggregate
```
**PhysicsShapeType:**
```typescript
BABYLON.PhysicsShapeType.SPHERE
BABYLON.PhysicsShapeType.BOX
BABYLON.PhysicsShapeType.CAPSULE
BABYLON.PhysicsShapeType.CYLINDER
BABYLON.PhysicsShapeType.CONVEX_HULL
BABYLON.PhysicsShapeType.MESH
BABYLON.PhysicsShapeType.HEIGHTFIELD
BABYLON.PhysicsShapeType.CONTAINER
```
**PhysicsAggregateParameters:**
```typescript
interface PhysicsAggregateParameters {
mass?: number; // 0 = static
restitution?: number; // Bounciness (0-1)
friction?: number; // Surface friction
startAsleep?: boolean; // Start inactive
ignoreChildren?: boolean; // Ignore child meshes
disableBidirectionalTransformation?: boolean;
pressure?: number; // For soft bodies
stiffness?: number; // For soft bodies
velocityIterations?: number;
positionIterations?: number;
}
```
**Properties:**
```typescript
aggregate.body: PhysicsBody // Physics body
aggregate.shape: PhysicsShape // Collision shape
aggregate.transformNode: TransformNode // Associated node
```
**Methods:**
```typescript
aggregate.dispose(): void
```
### BABYLON.PhysicsBody
Physics body control.
```typescript
body.setMassProperties(props: { mass?: number, inertia?: Vector3, centerOfMass?: Vector3 }): void
body.getMass(): number
body.setLinearVelocity(velocity: Vector3): void
body.getLinearVelocity(): Vector3
body.setAngularVelocity(velocity: Vector3): void
body.getAngularVelocity(): Vector3
body.applyForce(force: Vector3, location: Vector3): void
body.applyImpulse(impulse: Vector3, location: Vector3): void
body.setMotionType(motionType: PhysicsMotionType): void
body.getMotionType(): PhysicsMotionType
body.setLinearDamping(damping: number): void
body.setAngularDamping(damping: number): void
body.setCollisionCallbackEnabled(enabled: boolean): void
```
### BABYLON.PhysicsRaycastResult
Raycast result.
```typescript
scene.physicsEngine?.raycast(from: Vector3, to: Vector3): PhysicsRaycastResult
interface PhysicsRaycastResult {
hasHit: boolean;
hitPointWorld: Vector3;
hitNormalWorld: Vector3;
hitFraction: number;
body?: PhysicsBody;
}
```
---
## Animations
### BABYLON.Animation
Property animation.
#### Constructor
```typescript
new Animation(
name: string,
targetProperty: string,
framePerSecond: number,
dataType: number,
loopMode?: number,
enableBlending?: boolean
): Animation
```
**Data Types:**
```typescript
Animation.ANIMATIONTYPE_FLOAT
Animation.ANIMATIONTYPE_VECTOR2
Animation.ANIMATIONTYPE_VECTOR3
Animation.ANIMATIONTYPE_QUATERNION
Animation.ANIMATIONTYPE_MATRIX
Animation.ANIMATIONTYPE_COLOR3
Animation.ANIMATIONTYPE_COLOR4
Animation.ANIMATIONTYPE_SIZE
```
**Loop Modes:**
```typescript
Animation.ANIMATIONLOOPMODE_RELATIVE // Continue from current
Animation.ANIMATIONLOOPMODE_CYCLE // Loop
Animation.ANIMATIONLOOPMODE_CONSTANT // Stop at end
Animation.ANIMATIONLOOPMODE_YOYO // Ping-pong
```
#### Methods
```typescript
animation.setKeys(keys: IAnimationKey[]): void
interface IAnimationKey {
frame: number;
value: any;
inTangent?: any;
outTangent?: any;
interpolation?: AnimationKeyInterpolation;
}
// Helper
Animation.CreateAndStartAnimation(
name: string,
node: Node,
targetProperty: string,
framePerSecond: number,
totalFrame: number,
from: any,
to: any,
loopMode?: number,
easingFunction?: EasingFunction,
onAnimationEnd?: () => void
): Animatable
```
### BABYLON.AnimationGroup
Group of synchronized animations.
```typescript
const animationGroup = new BABYLON.AnimationGroup('group', scene);
animationGroup.addTargetedAnimation(animation: Animation, target: any): TargetedAnimation;
// Control
animationGroup.play(loop?: boolean): void
animationGroup.pause(): void
animationGroup.stop(): void
animationGroup.reset(): void
animationGroup.goToFrame(frame: number): void
animationGroup.speedRatio = 2.0; // 2x speed
```
---
## GUI
### BABYLON.GUI.AdvancedDynamicTexture
2D UI container.
```typescript
// Fullscreen UI
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI', true, scene);
// Mesh UI
const plane = BABYLON.MeshBuilder.CreatePlane('plane', {size: 2}, scene);
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(plane, 1024, 1024);
// Add controls
advancedTexture.addControl(control);
```
### Common Controls
```typescript
// Button
const button = BABYLON.GUI.Button.CreateSimpleButton('button', 'Click Me');
button.width = '150px';
button.height = '40px';
button.color = 'white';
button.background = 'green';
button.onPointerUpObservable.add(() => console.log('Clicked'));
// TextBlock
const text = new BABYLON.GUI.TextBlock();
text.text = 'Hello';
text.color = 'white';
text.fontSize = 24;
// Rectangle
const rect = new BABYLON.GUI.Rectangle();
rect.width = '400px';
rect.height = '200px';
rect.background = 'red';
// Image
const image = new BABYLON.GUI.Image('image', 'url');
image.width = '100px';
image.height = '100px';
// Slider
const slider = new BABYLON.GUI.Slider();
slider.minimum = 0;
slider.maximum = 100;
slider.value = 50;
slider.onValueChangedObservable.add((value) => console.log(value));
```
---
## Post-Processing
### BABYLON.DefaultRenderingPipeline
All-in-one post-processing.
```typescript
const pipeline = new BABYLON.DefaultRenderingPipeline(
'pipeline',
true, // HDR
scene,
[camera] // cameras
);
// FXAA
pipeline.fxaaEnabled = true;
// Bloom
pipeline.bloomEnabled = true;
pipeline.bloomThreshold = 0.8;
pipeline.bloomWeight = 0.5;
pipeline.bloomKernel = 64;
// Image processing
pipeline.imageProcessingEnabled = true;
pipeline.imageProcessing.contrast = 1.5;
pipeline.imageProcessing.exposure = 1.0;
pipeline.imageProcessing.toneMappingEnabled = true;
// Depth of field
pipeline.depthOfFieldEnabled = true;
pipeline.depthOfField.focusDistance = 2000;
pipeline.depthOfField.focalLength = 50;
// Chromatic aberration
pipeline.chromaticAberrationEnabled = true;
pipeline.chromaticAberration.aberrationAmount = 30;
// Grain
pipeline.grainEnabled = true;
pipeline.grain.intensity = 10;
// Sharpen
pipeline.sharpenEnabled = true;
pipeline.sharpen.edgeAmount = 0.3;
```
---
## Constants Reference
### Texture Constants
```typescript
// Wrap modes
Texture.CLAMP_ADDRESSMODE
Texture.WRAP_ADDRESSMODE
Texture.MIRROR_ADDRESSMODE
// Sampling modes
Texture.NEAREST_SAMPLINGMODE
Texture.BILINEAR_SAMPLINGMODE
Texture.TRILINEAR_SAMPLINGMODE
// Coordinate modes
Texture.EXPLICIT_MODE
Texture.SPHERICAL_MODE
Texture.PLANAR_MODE
Texture.CUBIC_MODE
Texture.PROJECTION_MODE
Texture.SKYBOX_MODE
Texture.INVCUBIC_MODE
Texture.EQUIRECTANGULAR_MODE
Texture.FIXED_EQUIRECTANGULAR_MODE
```
### Material Constants
```typescript
// Side orientation
Material.ClockWiseSideOrientation
Material.CounterClockWiseSideOrientation
// Fill modes
Material.PointFillMode
Material.WireFrameFillMode
Material.TriangleFillMode
// Alpha modes
Material.ALPHA_DISABLE
Material.ALPHA_ADD
Material.ALPHA_COMBINE
Material.ALPHA_SUBTRACT
Material.ALPHA_MULTIPLY
Material.ALPHA_MAXIMIZED
Material.ALPHA_ONEONE
Material.ALPHA_PREMULTIPLIED
Material.ALPHA_INTERPOLATE
```
---
This reference covers the most commonly used Babylon.js APIs. For complete documentation, visit: https://doc.babylonjs.com/
scripts/mesh_builder.py
#!/usr/bin/env python3
"""
Babylon.js Mesh Builder
Interactive tool for generating Babylon.js mesh creation code.
Supports all MeshBuilder shapes with full parameter customization.
Usage:
python3 mesh_builder.py --shape sphere --name mySphere --output meshes.js
python3 mesh_builder.py --shape box --params '{"size": 2}' --typescript
python3 mesh_builder.py --interactive
"""
import argparse
import json
import sys
from pathlib import Path
MESH_SHAPES = {
'box': {
'description': 'Rectangular box',
'params': {
'size': {'type': 'number', 'default': 1, 'description': 'Overall size'},
'width': {'type': 'number', 'description': 'Width (X axis)'},
'height': {'type': 'number', 'description': 'Height (Y axis)'},
'depth': {'type': 'number', 'description': 'Depth (Z axis)'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'sphere': {
'description': 'Sphere/ellipsoid',
'params': {
'diameter': {'type': 'number', 'default': 1, 'description': 'Overall diameter'},
'diameterX': {'type': 'number', 'description': 'X diameter'},
'diameterY': {'type': 'number', 'description': 'Y diameter'},
'diameterZ': {'type': 'number', 'description': 'Z diameter'},
'segments': {'type': 'number', 'default': 32, 'description': 'Segments'},
'arc': {'type': 'number', 'default': 1, 'description': 'Horizontal coverage (0-1)'},
'slice': {'type': 'number', 'default': 1, 'description': 'Vertical coverage (0-1)'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'cylinder': {
'description': 'Cylinder/cone',
'params': {
'height': {'type': 'number', 'default': 2, 'description': 'Height'},
'diameter': {'type': 'number', 'default': 1, 'description': 'Overall diameter'},
'diameterTop': {'type': 'number', 'description': 'Top diameter (for cone)'},
'diameterBottom': {'type': 'number', 'description': 'Bottom diameter'},
'tessellation': {'type': 'number', 'default': 24, 'description': 'Radial segments'},
'subdivisions': {'type': 'number', 'default': 1, 'description': 'Height subdivisions'},
'arc': {'type': 'number', 'default': 1, 'description': 'Arc coverage (0-1)'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'plane': {
'description': 'Flat plane',
'params': {
'size': {'type': 'number', 'default': 1, 'description': 'Overall size'},
'width': {'type': 'number', 'description': 'Width'},
'height': {'type': 'number', 'description': 'Height'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'ground': {
'description': 'Ground plane',
'params': {
'width': {'type': 'number', 'default': 1, 'description': 'Width'},
'height': {'type': 'number', 'default': 1, 'description': 'Height (depth)'},
'subdivisions': {'type': 'number', 'default': 1, 'description': 'Subdivisions'},
'subdivisionsX': {'type': 'number', 'description': 'X subdivisions'},
'subdivisionsY': {'type': 'number', 'description': 'Y subdivisions'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'torus': {
'description': 'Torus (donut)',
'params': {
'diameter': {'type': 'number', 'default': 1, 'description': 'Overall diameter'},
'thickness': {'type': 'number', 'default': 0.5, 'description': 'Tube thickness'},
'tessellation': {'type': 'number', 'default': 16, 'description': 'Radial segments'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'torus-knot': {
'description': 'Torus knot',
'params': {
'radius': {'type': 'number', 'default': 2, 'description': 'Overall radius'},
'tube': {'type': 'number', 'default': 0.5, 'description': 'Tube radius'},
'radialSegments': {'type': 'number', 'default': 32, 'description': 'Radial segments'},
'tubularSegments': {'type': 'number', 'default': 32, 'description': 'Tube segments'},
'p': {'type': 'number', 'default': 2, 'description': 'P parameter'},
'q': {'type': 'number', 'default': 3, 'description': 'Q parameter'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'capsule': {
'description': 'Capsule (cylinder with rounded ends)',
'params': {
'radius': {'type': 'number', 'default': 0.5, 'description': 'Radius'},
'height': {'type': 'number', 'default': 2, 'description': 'Height'},
'radiusTop': {'type': 'number', 'description': 'Top radius'},
'radiusBottom': {'type': 'number', 'description': 'Bottom radius'},
'tessellation': {'type': 'number', 'default': 16, 'description': 'Segments'},
'subdivisions': {'type': 'number', 'default': 1, 'description': 'Height subdivisions'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'lines': {
'description': 'Line segments',
'params': {
'points': {'type': 'vector3[]', 'description': 'Array of Vector3 points'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'ribbon': {
'description': 'Ribbon from path array',
'params': {
'pathArray': {'type': 'vector3[][]', 'description': '2D array of Vector3 paths'},
'closeArray': {'type': 'boolean', 'default': False, 'description': 'Close the ribbon'},
'closePath': {'type': 'boolean', 'default': False, 'description': 'Close each path'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'tube': {
'description': 'Tube along path',
'params': {
'path': {'type': 'vector3[]', 'description': 'Path curve'},
'radius': {'type': 'number', 'default': 1, 'description': 'Tube radius'},
'tessellation': {'type': 'number', 'default': 64, 'description': 'Radial segments'},
'cap': {'type': 'number', 'default': 0, 'description': 'Cap mode (0-3)'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'polyhedron': {
'description': 'Regular polyhedron',
'params': {
'type': {'type': 'number', 'default': 0, 'description': 'Type (0-19)'},
'size': {'type': 'number', 'default': 1, 'description': 'Size'},
'sizeX': {'type': 'number', 'description': 'X size'},
'sizeY': {'type': 'number', 'description': 'Y size'},
'sizeZ': {'type': 'number', 'description': 'Z size'},
'updatable': {'type': 'boolean', 'default': False}
}
},
'icosphere': {
'description': 'Geodesic sphere',
'params': {
'radius': {'type': 'number', 'default': 1, 'description': 'Radius'},
'radiusX': {'type': 'number', 'description': 'X radius'},
'radiusY': {'type': 'number', 'description': 'Y radius'},
'radiusZ': {'type': 'number', 'description': 'Z radius'},
'subdivisions': {'type': 'number', 'default': 4, 'description': 'Subdivisions'},
'flat': {'type': 'boolean', 'default': True, 'description': 'Flat shading'},
'updatable': {'type': 'boolean', 'default': False}
}
}
}
MATERIAL_PRESETS = {
'standard': {
'description': 'Basic Standard Material',
'code': """const material = new StandardMaterial('{name}Material', scene);
material.diffuseColor = new Color3(1, 0, 0);
material.specularColor = new Color3(0.5, 0.5, 0.5);
material.specularPower = 32;
{mesh}.material = material;"""
},
'pbr': {
'description': 'PBR Material',
'code': """const material = new PBRMaterial('{name}Material', scene);
material.metallic = 1.0;
material.roughness = 0.3;
material.baseColor = new Color3(0.9, 0.9, 0.9);
{mesh}.material = material;"""
},
'textured': {
'description': 'Textured Standard Material',
'code': """const material = new StandardMaterial('{name}Material', scene);
material.diffuseTexture = new Texture('path/to/texture.jpg', scene);
{mesh}.material = material;"""
}
}
def generate_mesh_code(shape, name, params, use_typescript, material_preset=None):
"""Generate mesh creation code."""
# Convert shape name
shape_func = ''.join(word.capitalize() for word in shape.split('-'))
# Build parameters
param_strs = []
for key, value in params.items():
if isinstance(value, bool):
param_strs.append(f'{key}: {str(value).lower()}')
elif isinstance(value, (int, float)):
param_strs.append(f'{key}: {value}')
elif isinstance(value, str):
param_strs.append(f'{key}: {value}') # Assume already formatted
params_str = ', '.join(param_strs) if param_strs else ''
# Generate code
code = f"const {name} = Create{shape_func}('{name}', {{ {params_str} }}, scene);"
# Add material if specified
if material_preset and material_preset in MATERIAL_PRESETS:
material_code = MATERIAL_PRESETS[material_preset]['code'].format(
name=name,
mesh=name
)
code = f"{code}\n\n{material_code}"
return code
def generate_imports(shapes, use_typescript, include_materials):
"""Generate imports for mesh builders."""
ext = '' if use_typescript else '.js'
imports = set()
# Shape imports
for shape in shapes:
shape_func = ''.join(word.capitalize() for word in shape.split('-'))
builder_name = shape.split('-')[0] + 'Builder' # e.g., boxBuilder, sphereBuilder
if shape in ['lines', 'ribbon', 'tube']:
imports.add(f"import {{ Create{shape_func} }} from '@babylonjs/core/Meshes/Builders/{shape}Builder{ext}';")
else:
imports.add(f"import {{ Create{shape_func} }} from '@babylonjs/core/Meshes/Builders/{builder_name}{ext}';")
# Material imports
if include_materials:
imports.add(f"import {{ StandardMaterial }} from '@babylonjs/core/Materials/standardMaterial{ext}';")
imports.add(f"import {{ PBRMaterial }} from '@babylonjs/core/Materials/PBR/pbrMaterial{ext}';")
imports.add(f"import {{ Texture }} from '@babylonjs/core/Materials/Textures/texture{ext}';")
imports.add(f"import {{ Color3 }} from '@babylonjs/core/Maths/math.color{ext}';")
return '\n'.join(sorted(imports))
def interactive_mode():
"""Interactive CLI for mesh building."""
print("\n🎨 Babylon.js Mesh Builder - Interactive Mode\n")
meshes = []
while True:
# Shape selection
print("\nSelect mesh shape:")
shapes_list = list(MESH_SHAPES.keys())
for i, shape in enumerate(shapes_list, 1):
desc = MESH_SHAPES[shape]['description']
print(f" {i:2d}. {shape:15s} - {desc}")
shape_choice = input("\nEnter number (or 'done' to finish): ").strip()
if shape_choice.lower() == 'done':
break
shape = shapes_list[int(shape_choice) - 1]
# Mesh name
default_name = f"{shape.replace('-', '')}1"
name = input(f"\nMesh name (default: {default_name}): ").strip() or default_name
# Parameters
print(f"\nConfigure {shape} parameters (press Enter for defaults):")
params = {}
for param_name, param_info in MESH_SHAPES[shape]['params'].items():
if param_info['type'] in ['vector3[]', 'vector3[][]']:
# Skip complex types in interactive mode
continue
prompt = f" {param_name}"
if 'default' in param_info:
prompt += f" (default: {param_info['default']})"
if 'description' in param_info:
prompt += f" - {param_info['description']}"
prompt += ": "
value = input(prompt).strip()
if value:
if param_info['type'] == 'boolean':
params[param_name] = value.lower() in ['true', 'yes', 'y', '1']
elif param_info['type'] == 'number':
params[param_name] = float(value) if '.' in value else int(value)
else:
params[param_name] = value
# Material
print("\nAdd material?")
print(" 1. None")
print(" 2. Standard Material")
print(" 3. PBR Material")
print(" 4. Textured Material")
material_choice = input("\nEnter number (default: 1): ").strip() or "1"
material_preset = None
if material_choice == '2':
material_preset = 'standard'
elif material_choice == '3':
material_preset = 'pbr'
elif material_choice == '4':
material_preset = 'textured'
meshes.append({
'shape': shape,
'name': name,
'params': params,
'material': material_preset
})
print(f"\n✅ Added {name}")
if not meshes:
print("\n❌ No meshes created")
return
# Generate code
use_typescript = input("\nGenerate TypeScript? (y/N): ").strip().lower() == 'y'
ext = 'ts' if use_typescript else 'js'
output_file = input(f"\nOutput file (default: meshes.{ext}): ").strip() or f"meshes.{ext}"
# Build code
shapes = list(set(m['shape'] for m in meshes))
has_materials = any(m['material'] for m in meshes)
imports = generate_imports(shapes, use_typescript, has_materials)
mesh_codes = []
for mesh in meshes:
code = generate_mesh_code(
mesh['shape'],
mesh['name'],
mesh['params'],
use_typescript,
mesh['material']
)
mesh_codes.append(code)
final_code = f"""// Generated by Babylon.js Mesh Builder
{imports}
export function createMeshes(scene{': Scene' if use_typescript else ''}) {{
{chr(10).join(' ' + line for mc in mesh_codes for line in mc.split(chr(10)))}
}}
"""
Path(output_file).write_text(final_code)
print(f"\n✅ Generated: {output_file}")
print(f"📝 Created {len(meshes)} mesh(es)")
def main():
parser = argparse.ArgumentParser(
description='Generate Babylon.js mesh creation code',
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
'--shape',
choices=list(MESH_SHAPES.keys()),
help='Mesh shape'
)
parser.add_argument(
'--name',
default='mesh1',
help='Mesh name (default: mesh1)'
)
parser.add_argument(
'--params',
type=json.loads,
default={},
help='Mesh parameters as JSON'
)
parser.add_argument(
'--material',
choices=list(MATERIAL_PRESETS.keys()),
help='Material preset'
)
parser.add_argument(
'--typescript',
action='store_true',
help='Generate TypeScript'
)
parser.add_argument(
'--output',
help='Output file'
)
parser.add_argument(
'--interactive',
action='store_true',
help='Interactive mode'
)
parser.add_argument(
'--list-shapes',
action='store_true',
help='List available shapes'
)
args = parser.parse_args()
# List shapes
if args.list_shapes:
print("\nAvailable mesh shapes:\n")
for shape, info in MESH_SHAPES.items():
print(f" {shape}:")
print(f" {info['description']}")
print(f" Parameters:")
for param, details in info['params'].items():
default = f" (default: {details['default']})" if 'default' in details else ""
desc = details.get('description', '')
print(f" - {param}: {details['type']}{default} - {desc}")
print()
return
# Interactive mode
if args.interactive or not args.shape:
interactive_mode()
return
# Generate from args
ext = 'ts' if args.typescript else 'js'
output_file = args.output or f"mesh_{args.name}.{ext}"
shapes = [args.shape]
has_materials = args.material is not None
imports = generate_imports(shapes, args.typescript, has_materials)
mesh_code = generate_mesh_code(
args.shape,
args.name,
args.params,
args.typescript,
args.material
)
final_code = f"""// Generated by Babylon.js Mesh Builder
{imports}
export function createMesh(scene{': Scene' if args.typescript else ''}) {{
{chr(10).join(' ' + line for line in mesh_code.split(chr(10)))}
}}
"""
Path(output_file).write_text(final_code)
print(f"✅ Generated: {output_file}")
if __name__ == '__main__':
main()
scripts/scene_generator.py
#!/usr/bin/env python3
"""
Babylon.js Scene Generator
Generates Babylon.js scene boilerplate with various configurations.
Supports multiple scene types, cameras, lighting setups, and physics.
Usage:
python3 scene_generator.py --type basic --name MyScene --output scene.js
python3 scene_generator.py --type physics --camera arc-rotate --typescript
python3 scene_generator.py --interactive
"""
import argparse
import sys
from pathlib import Path
SCENE_TYPES = {
'basic': {
'description': 'Basic scene with camera, light, and ground',
'includes': ['camera', 'light', 'ground']
},
'physics': {
'description': 'Scene with Havok physics enabled',
'includes': ['camera', 'light', 'ground', 'physics', 'sphere']
},
'pbr': {
'description': 'PBR materials showcase scene',
'includes': ['camera', 'light', 'pbr-meshes', 'environment']
},
'model-viewer': {
'description': 'GLTF model loading and viewing',
'includes': ['arc-camera', 'light', 'model-loader', 'environment']
},
'vr': {
'description': 'WebXR VR scene',
'includes': ['camera', 'light', 'ground', 'webxr']
},
'particles': {
'description': 'Particle system showcase',
'includes': ['camera', 'light', 'particles']
},
'gui': {
'description': 'Scene with 2D GUI elements',
'includes': ['camera', 'light', 'ground', 'gui']
},
'post-processing': {
'description': 'Scene with post-processing effects',
'includes': ['camera', 'light', 'meshes', 'post-processing']
}
}
CAMERA_TYPES = {
'free': 'FreeCamera',
'arc-rotate': 'ArcRotateCamera',
'universal': 'UniversalCamera',
'follow': 'FollowCamera'
}
def generate_imports(scene_type, use_typescript, camera_type):
"""Generate ES6 imports based on scene configuration."""
if use_typescript:
imports = [
"import { Engine } from '@babylonjs/core/Engines/engine';",
"import { Scene } from '@babylonjs/core/scene';",
"import { Vector3 } from '@babylonjs/core/Maths/math.vector';",
"import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight';",
]
else:
imports = [
"import { Engine } from '@babylonjs/core/Engines/engine.js';",
"import { Scene } from '@babylonjs/core/scene.js';",
"import { Vector3 } from '@babylonjs/core/Maths/math.vector.js';",
"import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight.js';",
]
# Camera imports
camera_import_map = {
'free': "FreeCamera } from '@babylonjs/core/Cameras/freeCamera",
'arc-rotate': "ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera",
'universal': "UniversalCamera } from '@babylonjs/core/Cameras/universalCamera",
'follow': "FollowCamera } from '@babylonjs/core/Cameras/followCamera"
}
camera_import = camera_import_map.get(camera_type, camera_import_map['arc-rotate'])
imports.append(f"import {{ {camera_import}{'js' if not use_typescript else ''}';}}")
config = SCENE_TYPES[scene_type]
# Mesh builders
if 'ground' in config['includes'] or 'meshes' in config['includes']:
if use_typescript:
imports.append("import { CreateGround } from '@babylonjs/core/Meshes/Builders/groundBuilder';")
imports.append("import { CreateSphere } from '@babylonjs/core/Meshes/Builders/sphereBuilder';")
imports.append("import { CreateBox } from '@babylonjs/core/Meshes/Builders/boxBuilder';")
else:
imports.append("import { CreateGround } from '@babylonjs/core/Meshes/Builders/groundBuilder.js';")
imports.append("import { CreateSphere } from '@babylonjs/core/Meshes/Builders/sphereBuilder.js';")
imports.append("import { CreateBox } from '@babylonjs/core/Meshes/Builders/boxBuilder.js';")
# Physics
if 'physics' in config['includes']:
if use_typescript:
imports.append("import HavokPhysics from '@babylonjs/havok';")
imports.append("import { HavokPlugin } from '@babylonjs/core/Physics/v2/Plugins/havokPlugin';")
imports.append("import { PhysicsAggregate } from '@babylonjs/core/Physics/v2/physicsAggregate';")
imports.append("import { PhysicsShapeType } from '@babylonjs/core/Physics/v2/IPhysicsEnginePlugin';")
else:
imports.append("import HavokPhysics from '@babylonjs/havok';")
imports.append("import { HavokPlugin } from '@babylonjs/core/Physics/v2/Plugins/havokPlugin.js';")
imports.append("import { PhysicsAggregate } from '@babylonjs/core/Physics/v2/physicsAggregate.js';")
imports.append("import { PhysicsShapeType } from '@babylonjs/core/Physics/v2/IPhysicsEnginePlugin.js';")
# PBR
if 'pbr-meshes' in config['includes']:
if use_typescript:
imports.append("import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';")
else:
imports.append("import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial.js';")
# Environment
if 'environment' in config['includes']:
if use_typescript:
imports.append("import { CubeTexture } from '@babylonjs/core/Materials/Textures/cubeTexture';")
else:
imports.append("import { CubeTexture } from '@babylonjs/core/Materials/Textures/cubeTexture.js';")
# Model loader
if 'model-loader' in config['includes']:
if use_typescript:
imports.append("import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader';")
imports.append("import '@babylonjs/loaders/glTF';")
else:
imports.append("import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader.js';")
imports.append("import '@babylonjs/loaders/glTF';")
# WebXR
if 'webxr' in config['includes']:
if use_typescript:
imports.append("import '@babylonjs/core/Helpers/sceneHelpers';")
else:
imports.append("import '@babylonjs/core/Helpers/sceneHelpers.js';")
# GUI
if 'gui' in config['includes']:
if use_typescript:
imports.append("import { AdvancedDynamicTexture } from '@babylonjs/gui/2D/advancedDynamicTexture';")
imports.append("import { Button } from '@babylonjs/gui/2D/controls/button';")
else:
imports.append("import { AdvancedDynamicTexture } from '@babylonjs/gui/2D/advancedDynamicTexture.js';")
imports.append("import { Button } from '@babylonjs/gui/2D/controls/button.js';")
# Particles
if 'particles' in config['includes']:
if use_typescript:
imports.append("import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';")
imports.append("import { Texture } from '@babylonjs/core/Materials/Textures/texture';")
else:
imports.append("import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem.js';")
imports.append("import { Texture } from '@babylonjs/core/Materials/Textures/texture.js';")
# Post-processing
if 'post-processing' in config['includes']:
if use_typescript:
imports.append("import { DefaultRenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline';")
else:
imports.append("import { DefaultRenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.js';")
return '\n'.join(imports)
def generate_camera_code(camera_type, use_typescript):
"""Generate camera setup code."""
if camera_type == 'free':
return """ // Create FreeCamera
const camera = new FreeCamera('camera', new Vector3(0, 5, -10), scene);
camera.setTarget(Vector3.Zero());
camera.attachControl(canvas, true);
camera.speed = 0.5;
camera.angularSensibility = 2000;"""
elif camera_type == 'arc-rotate':
return """ // Create ArcRotateCamera
const camera = new ArcRotateCamera(
'camera',
-Math.PI / 2,
Math.PI / 2.5,
10,
Vector3.Zero(),
scene
);
camera.attachControl(canvas, true);
camera.lowerRadiusLimit = 5;
camera.upperRadiusLimit = 50;"""
elif camera_type == 'universal':
return """ // Create UniversalCamera
const camera = new UniversalCamera('camera', new Vector3(0, 5, -10), scene);
camera.setTarget(Vector3.Zero());
camera.attachControl(canvas, true);
camera.checkCollisions = true;
camera.applyGravity = true;"""
elif camera_type == 'follow':
return """ // Create FollowCamera
const camera = new FollowCamera('camera', new Vector3(0, 10, -10), scene);
camera.radius = 10;
camera.heightOffset = 5;
camera.rotationOffset = 0;
camera.cameraAcceleration = 0.05;
camera.maxCameraSpeed = 10;
camera.attachControl(canvas, true);"""
return ""
def generate_scene_code(scene_type, camera_type, use_typescript):
"""Generate scene setup code based on type."""
config = SCENE_TYPES[scene_type]
code = []
# Camera
code.append(generate_camera_code(camera_type, use_typescript))
# Light
code.append("""
// Create light
const light = new HemisphericLight('light', new Vector3(0, 1, 0), scene);
light.intensity = 0.7;""")
# Ground
if 'ground' in config['includes']:
code.append("""
// Create ground
const ground = CreateGround('ground', { width: 10, height: 10 }, scene);""")
# Physics
if 'physics' in config['includes']:
code.append("""
// Initialize Havok physics
const havokInstance = await HavokPhysics();
const havokPlugin = new HavokPlugin(true, havokInstance);
scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin);
// Create sphere with physics
const sphere = CreateSphere('sphere', { diameter: 2 }, scene);
sphere.position.y = 5;
const sphereAggregate = new PhysicsAggregate(
sphere,
PhysicsShapeType.SPHERE,
{ mass: 1, restitution: 0.75 },
scene
);
const groundAggregate = new PhysicsAggregate(
ground,
PhysicsShapeType.BOX,
{ mass: 0 },
scene
);""")
# PBR materials
if 'pbr-meshes' in config['includes']:
code.append("""
// Create PBR materials
const pbrMaterial = new PBRMaterial('pbr', scene);
pbrMaterial.metallic = 1.0;
pbrMaterial.roughness = 0.3;
pbrMaterial.baseColor = new BABYLON.Color3(0.9, 0.9, 0.9);
const sphere = CreateSphere('sphere', { diameter: 2 }, scene);
sphere.position.y = 1;
sphere.material = pbrMaterial;
const box = CreateBox('box', { size: 1.5 }, scene);
box.position.set(3, 0.75, 0);
const boxMaterial = new PBRMaterial('boxMaterial', scene);
boxMaterial.metallic = 0.0;
boxMaterial.roughness = 0.8;
boxMaterial.baseColor = new BABYLON.Color3(0.8, 0.2, 0.2);
box.material = boxMaterial;""")
# Environment
if 'environment' in config['includes']:
code.append("""
// Create default environment
const env = scene.createDefaultEnvironment({
createGround: true,
createSkybox: true,
skyboxSize: 150
});""")
# Model loader
if 'model-loader' in config['includes']:
code.append("""
// Load GLTF model
const result = await SceneLoader.ImportMeshAsync(
null,
'https://assets.babylonjs.com/meshes/',
'village.glb',
scene
);
console.log('Loaded meshes:', result.meshes.length);""")
# WebXR
if 'webxr' in config['includes']:
code.append("""
// Enable WebXR
const env = scene.createDefaultEnvironment();
const xr = await scene.createDefaultXRExperienceAsync({
floorMeshes: [env.ground]
});""")
# GUI
if 'gui' in config['includes']:
code.append("""
// Create 2D UI
const advancedTexture = AdvancedDynamicTexture.CreateFullscreenUI('UI');
const button = Button.CreateSimpleButton('button', 'Click Me');
button.width = '150px';
button.height = '40px';
button.color = 'white';
button.background = 'green';
button.onPointerUpObservable.add(() => {
console.log('Button clicked');
});
advancedTexture.addControl(button);""")
# Particles
if 'particles' in config['includes']:
code.append("""
// Create particle system
const particleSystem = new ParticleSystem('particles', 2000, scene);
particleSystem.particleTexture = new Texture('https://assets.babylonjs.com/textures/flare.png', scene);
particleSystem.emitter = new Vector3(0, 5, 0);
particleSystem.minEmitBox = new Vector3(-1, 0, 0);
particleSystem.maxEmitBox = new Vector3(1, 0, 0);
particleSystem.color1 = new BABYLON.Color4(0.7, 0.8, 1.0, 1.0);
particleSystem.color2 = new BABYLON.Color4(0.2, 0.5, 1.0, 1.0);
particleSystem.colorDead = new BABYLON.Color4(0, 0, 0.2, 0.0);
particleSystem.minSize = 0.1;
particleSystem.maxSize = 0.5;
particleSystem.minLifeTime = 0.3;
particleSystem.maxLifeTime = 1.5;
particleSystem.emitRate = 1500;
particleSystem.direction1 = new Vector3(-1, 8, 1);
particleSystem.direction2 = new Vector3(1, 8, -1);
particleSystem.gravity = new Vector3(0, -9.81, 0);
particleSystem.start();""")
# Post-processing
if 'post-processing' in config['includes']:
code.append("""
// Add post-processing
const pipeline = new DefaultRenderingPipeline('pipeline', true, scene, [camera]);
pipeline.fxaaEnabled = true;
pipeline.samples = 4;
pipeline.bloomEnabled = true;
pipeline.bloomThreshold = 0.8;
pipeline.bloomWeight = 0.5;
pipeline.bloomKernel = 64;
// Create some meshes
const sphere = CreateSphere('sphere', { diameter: 2 }, scene);
sphere.position.y = 1;
const box = CreateBox('box', { size: 1.5 }, scene);
box.position.set(3, 0.75, 0);
const ground = CreateGround('ground', { width: 10, height: 10 }, scene);""")
return '\n'.join(code)
def generate_scene_file(scene_type, camera_type, use_typescript, scene_name):
"""Generate complete scene file."""
ext = 'ts' if use_typescript else 'js'
imports = generate_imports(scene_type, use_typescript, camera_type)
scene_code = generate_scene_code(scene_type, camera_type, use_typescript)
is_async = 'physics' in SCENE_TYPES[scene_type]['includes'] or \
'model-loader' in SCENE_TYPES[scene_type]['includes'] or \
'webxr' in SCENE_TYPES[scene_type]['includes']
template = f"""// {scene_name} - Generated by Babylon.js Scene Generator
{imports}
// Get canvas element
const canvas = document.getElementById('renderCanvas'){' as HTMLCanvasElement' if use_typescript else ''};
// Create engine
const engine = new Engine(canvas, true, {{
preserveDrawingBuffer: true,
stencil: true
}});
// Create scene
const createScene = {'async ' if is_async else ''}function(){': Scene' if use_typescript else ''} {{
const scene = new Scene(engine);
{scene_code}
return scene;
}};
// Initialize and run
{'(async () => {' if is_async else ''}
const scene = {'await ' if is_async else ''}createScene();
// Run render loop
engine.runRenderLoop(() => {{
scene.render();
}});
// Handle resize
window.addEventListener('resize', () => {{
engine.resize();
}});
{'})();' if is_async else ''}
"""
return template
def interactive_mode():
"""Interactive CLI for scene generation."""
print("\n🎮 Babylon.js Scene Generator - Interactive Mode\n")
# Scene type
print("Select scene type:")
for i, (key, config) in enumerate(SCENE_TYPES.items(), 1):
print(f" {i}. {key}: {config['description']}")
scene_choice = input("\nEnter number (1-8): ").strip()
scene_type = list(SCENE_TYPES.keys())[int(scene_choice) - 1]
# Camera type
print("\nSelect camera type:")
for i, (key, value) in enumerate(CAMERA_TYPES.items(), 1):
print(f" {i}. {key}: {value}")
camera_choice = input("\nEnter number (1-4, default 2): ").strip() or "2"
camera_type = list(CAMERA_TYPES.keys())[int(camera_choice) - 1]
# TypeScript
use_typescript = input("\nUse TypeScript? (y/N): ").strip().lower() == 'y'
# Scene name
scene_name = input("\nScene name (default: MyScene): ").strip() or "MyScene"
# Output file
ext = 'ts' if use_typescript else 'js'
default_output = f"{scene_name.lower().replace(' ', '_')}.{ext}"
output_file = input(f"\nOutput file (default: {default_output}): ").strip() or default_output
# Generate
print(f"\n✨ Generating {scene_type} scene...")
code = generate_scene_file(scene_type, camera_type, use_typescript, scene_name)
Path(output_file).write_text(code)
print(f"✅ Scene generated: {output_file}")
# Instructions
print(f"\n📝 Next steps:")
print(f" 1. Install dependencies: npm install @babylonjs/core @babylonjs/loaders")
if 'gui' in SCENE_TYPES[scene_type]['includes']:
print(f" npm install @babylonjs/gui")
if 'physics' in SCENE_TYPES[scene_type]['includes']:
print(f" npm install @babylonjs/havok")
print(f" 2. Create HTML file with <canvas id='renderCanvas'></canvas>")
print(f" 3. Import this scene file")
print(f" 4. Run dev server")
def main():
parser = argparse.ArgumentParser(
description='Generate Babylon.js scene boilerplate',
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
'--type',
choices=list(SCENE_TYPES.keys()),
help='Scene type'
)
parser.add_argument(
'--camera',
choices=list(CAMERA_TYPES.keys()),
default='arc-rotate',
help='Camera type (default: arc-rotate)'
)
parser.add_argument(
'--typescript',
action='store_true',
help='Generate TypeScript instead of JavaScript'
)
parser.add_argument(
'--name',
default='MyScene',
help='Scene name (default: MyScene)'
)
parser.add_argument(
'--output',
help='Output file path'
)
parser.add_argument(
'--interactive',
action='store_true',
help='Interactive mode'
)
parser.add_argument(
'--list-types',
action='store_true',
help='List available scene types'
)
args = parser.parse_args()
# List types
if args.list_types:
print("\nAvailable scene types:\n")
for key, config in SCENE_TYPES.items():
print(f" {key}:")
print(f" {config['description']}")
print(f" Includes: {', '.join(config['includes'])}\n")
return
# Interactive mode
if args.interactive or not args.type:
interactive_mode()
return
# Generate from args
ext = 'ts' if args.typescript else 'js'
output_file = args.output or f"{args.name.lower().replace(' ', '_')}.{ext}"
print(f"✨ Generating {args.type} scene...")
code = generate_scene_file(args.type, args.camera, args.typescript, args.name)
Path(output_file).write_text(code)
print(f"✅ Scene generated: {output_file}")
if __name__ == '__main__':
main()
SKILL.md
---
name: babylonjs-engine
description: Comprehensive skill for Babylon.js 3D web rendering engine. Use this skill when building real-time 3D experiences, browser-based games, interactive visualizations, or immersive web applications. Triggers on tasks involving Babylon.js, 3D scenes, WebGL/WebGPU rendering, entity-component systems, physics simulations, PBR materials, shadow mapping, or 3D model loading. Alternative to Three.js with built-in editor integration and game engine features.
---
# Babylon.js Engine Skill
## Related Skills
- threejs-webgl: Alternative 3D engine
- react-three-fiber: React integration for 3D
- gsap-scrolltrigger: Animation library
- motion-framer: UI animations
## Core Concepts
### 1. Engine and Scene Initialization
**Basic Setup**
```javascript
// Get canvas element
const canvas = document.getElementById('renderCanvas');
// Create engine
const engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true
});
// Create scene
const scene = new BABYLON.Scene(engine);
// Render loop
engine.runRenderLoop(() => {
scene.render();
});
// Handle resize
window.addEventListener('resize', () => {
engine.resize();
});
```
**ES6/TypeScript Setup**
```typescript
import { Engine } from '@babylonjs/core/Engines/engine';
import { Scene } from '@babylonjs/core/scene';
import { FreeCamera } from '@babylonjs/core/Cameras/freeCamera';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight';
import { CreateSphere } from '@babylonjs/core/Meshes/Builders/sphereBuilder';
const canvas = document.getElementById('renderCanvas') as HTMLCanvasElement;
const engine = new Engine(canvas);
const scene = new Scene(engine);
// Camera setup
const camera = new FreeCamera('camera1', new Vector3(0, 5, -10), scene);
camera.setTarget(Vector3.Zero());
camera.attachControl(canvas, true);
// Lighting
const light = new HemisphericLight('light1', new Vector3(0, 1, 0), scene);
light.intensity = 0.7;
// Create mesh
const sphere = CreateSphere('sphere1', { segments: 16, diameter: 2 }, scene);
sphere.position.y = 2;
// Render
engine.runRenderLoop(() => {
scene.render();
});
```
**Scene Configuration Options**
```javascript
const scene = new BABYLON.Scene(engine, {
// Optimize for large mesh counts
useGeometryUniqueIdsMap: true,
useMaterialMeshMap: true,
useClonedMeshMap: true
});
```
### 2. Camera Systems
**Free Camera (FPS-style)**
```javascript
const camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5, -10), scene);
camera.setTarget(BABYLON.Vector3.Zero());
camera.attachControl(canvas, true);
// Movement settings
camera.speed = 0.5;
camera.angularSensibility = 2000;
camera.keysUp = [87]; // W
camera.keysDown = [83]; // S
camera.keysLeft = [65]; // A
camera.keysRight = [68]; // D
```
**Arc Rotate Camera (Orbit)**
```javascript
const camera = new BABYLON.ArcRotateCamera(
'camera',
-Math.PI / 2, // alpha (horizontal rotation)
Math.PI / 2.5, // beta (vertical rotation)
15, // radius (distance)
new BABYLON.Vector3(0, 0, 0), // target
scene
);
camera.attachControl(canvas, true);
// Constraints
camera.lowerRadiusLimit = 5;
camera.upperRadiusLimit = 50;
camera.lowerBetaLimit = 0.1;
camera.upperBetaLimit = Math.PI / 2;
```
**Universal Camera (Advanced)**
```javascript
const camera = new BABYLON.UniversalCamera('camera', new BABYLON.Vector3(0, 5, -10), scene);
camera.setTarget(BABYLON.Vector3.Zero());
camera.attachControl(canvas, true);
// Collision detection
camera.checkCollisions = true;
camera.applyGravity = true;
camera.ellipsoid = new BABYLON.Vector3(1, 1, 1);
```
### 3. Lighting Systems
**Hemispheric Light (Ambient)**
```javascript
const light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.7;
light.diffuse = new BABYLON.Color3(1, 1, 1);
light.specular = new BABYLON.Color3(1, 1, 1);
light.groundColor = new BABYLON.Color3(0, 0, 0);
```
**Directional Light (Sun-like)**
```javascript
const light = new BABYLON.DirectionalLight('dirLight', new BABYLON.Vector3(-1, -2, -1), scene);
light.position = new BABYLON.Vector3(20, 40, 20);
light.intensity = 0.5;
// Shadow setup
const shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
shadowGenerator.useExponentialShadowMap = true;
```
**Point Light (Omni-directional)**
```javascript
const light = new BABYLON.PointLight('pointLight', new BABYLON.Vector3(0, 10, 0), scene);
light.intensity = 0.7;
light.diffuse = new BABYLON.Color3(1, 0, 0);
light.specular = new BABYLON.Color3(0, 1, 0);
// Range and falloff
light.range = 100;
light.radius = 0.1;
```
**Spot Light (Focused)**
```javascript
const light = new BABYLON.SpotLight(
'spotLight',
new BABYLON.Vector3(0, 10, 0), // position
new BABYLON.Vector3(0, -1, 0), // direction
Math.PI / 3, // angle
2, // exponent
scene
);
light.intensity = 0.8;
```
**Light Optimization (Include Only Specific Meshes)**
```javascript
// Only affect specific meshes
light.includedOnlyMeshes = [mesh1, mesh2, mesh3];
// Or exclude specific meshes
light.excludedMeshes = [mesh4, mesh5];
```
### 4. Mesh Creation
**Built-in Shapes**
```javascript
// Box
const box = BABYLON.MeshBuilder.CreateBox('box', {
size: 2,
width: 2,
height: 2,
depth: 2
}, scene);
// Sphere
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {
diameter: 2,
segments: 32,
diameterX: 2,
diameterY: 2,
diameterZ: 2,
arc: 1,
slice: 1
}, scene);
// Cylinder
const cylinder = BABYLON.MeshBuilder.CreateCylinder('cylinder', {
height: 3,
diameter: 2,
tessellation: 24
}, scene);
// Plane
const plane = BABYLON.MeshBuilder.CreatePlane('plane', {
size: 5,
width: 5,
height: 5
}, scene);
// Ground
const ground = BABYLON.MeshBuilder.CreateGround('ground', {
width: 10,
height: 10,
subdivisions: 2
}, scene);
// Ground from heightmap
const ground = BABYLON.MeshBuilder.CreateGroundFromHeightMap('ground', 'heightmap.png', {
width: 100,
height: 100,
subdivisions: 100,
minHeight: 0,
maxHeight: 10
}, scene);
// Torus
const torus = BABYLON.MeshBuilder.CreateTorus('torus', {
diameter: 3,
thickness: 1,
tessellation: 16
}, scene);
// TorusKnot
const torusKnot = BABYLON.MeshBuilder.CreateTorusKnot('torusKnot', {
radius: 2,
tube: 0.6,
radialSegments: 64,
tubularSegments: 8,
p: 2,
q: 3
}, scene);
```
**Mesh Transformations**
```javascript
// Position
mesh.position = new BABYLON.Vector3(0, 5, 10);
mesh.position.x = 5;
mesh.position.y = 2;
// Rotation (radians)
mesh.rotation = new BABYLON.Vector3(0, Math.PI / 2, 0);
mesh.rotation.y = Math.PI / 4;
// Scaling
mesh.scaling = new BABYLON.Vector3(2, 2, 2);
mesh.scaling.x = 1.5;
// Look at
mesh.lookAt(new BABYLON.Vector3(0, 0, 0));
// Parent-child relationships
childMesh.parent = parentMesh;
```
**Mesh Properties**
```javascript
// Visibility
mesh.isVisible = true;
mesh.visibility = 0.5; // 0 = invisible, 1 = fully visible
// Picking
mesh.isPickable = true;
mesh.checkCollisions = true;
// Culling
mesh.cullingStrategy = BABYLON.AbstractMesh.CULLINGSTRATEGY_BOUNDINGSPHERE_ONLY;
// Receive shadows
mesh.receiveShadows = true;
```
### 5. Materials
**Standard Material**
```javascript
const material = new BABYLON.StandardMaterial('material', scene);
// Colors
material.diffuseColor = new BABYLON.Color3(1, 0, 1);
material.specularColor = new BABYLON.Color3(0.5, 0.6, 0.87);
material.emissiveColor = new BABYLON.Color3(0, 0, 0);
material.ambientColor = new BABYLON.Color3(0.23, 0.98, 0.53);
// Textures
material.diffuseTexture = new BABYLON.Texture('diffuse.png', scene);
material.specularTexture = new BABYLON.Texture('specular.png', scene);
material.emissiveTexture = new BABYLON.Texture('emissive.png', scene);
material.ambientTexture = new BABYLON.Texture('ambient.png', scene);
material.bumpTexture = new BABYLON.Texture('normal.png', scene);
material.opacityTexture = new BABYLON.Texture('opacity.png', scene);
// Properties
material.alpha = 0.8;
material.backFaceCulling = true;
material.wireframe = false;
material.specularPower = 64;
// Apply to mesh
mesh.material = material;
```
**PBR Material (Physically Based Rendering)**
```javascript
const pbr = new BABYLON.PBRMaterial('pbr', scene);
// Metallic workflow
pbr.albedoColor = new BABYLON.Color3(1, 1, 1);
pbr.albedoTexture = new BABYLON.Texture('albedo.png', scene);
pbr.metallic = 1.0;
pbr.roughness = 0.5;
pbr.metallicTexture = new BABYLON.Texture('metallic.png', scene);
// Or specular workflow
pbr.albedoTexture = new BABYLON.Texture('albedo.png', scene);
pbr.reflectivityTexture = new BABYLON.Texture('reflectivity.png', scene);
// Environment
pbr.environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData('environment.dds', scene);
// Other maps
pbr.bumpTexture = new BABYLON.Texture('normal.png', scene);
pbr.ambientTexture = new BABYLON.Texture('ao.png', scene);
pbr.emissiveTexture = new BABYLON.Texture('emissive.png', scene);
mesh.material = pbr;
```
**Multi-Materials**
```javascript
const multiMat = new BABYLON.MultiMaterial('multiMat', scene);
multiMat.subMaterials.push(material1);
multiMat.subMaterials.push(material2);
multiMat.subMaterials.push(material3);
mesh.material = multiMat;
mesh.subMeshes = [];
mesh.subMeshes.push(new BABYLON.SubMesh(0, 0, verticesCount, 0, indicesCount1, mesh));
mesh.subMeshes.push(new BABYLON.SubMesh(1, 0, verticesCount, indicesCount1, indicesCount2, mesh));
```
### 6. Model Loading
**GLTF/GLB Import**
```javascript
// Append to scene
BABYLON.SceneLoader.Append('path/to/', 'model.gltf', scene, function(scene) {
console.log('Model loaded');
});
// Import mesh
BABYLON.SceneLoader.ImportMesh('', 'path/to/', 'model.gltf', scene, function(meshes) {
const mesh = meshes[0];
mesh.position.y = 5;
});
// Async version
const result = await BABYLON.SceneLoader.ImportMeshAsync(
null, // all meshes
'https://assets.babylonjs.com/meshes/',
'village.glb',
scene
);
console.log('Loaded meshes:', result.meshes);
// Load from binary
const result = await BABYLON.SceneLoader.AppendAsync(
'',
'data:' + arrayBuffer,
scene
);
```
**Asset Manager (Batch Loading)**
```javascript
const assetsManager = new BABYLON.AssetsManager(scene);
// Add mesh task
const meshTask = assetsManager.addMeshTask('model', '', 'path/to/', 'model.gltf');
meshTask.onSuccess = function(task) {
task.loadedMeshes[0].position = new BABYLON.Vector3(0, 0, 0);
};
// Add texture task
const textureTask = assetsManager.addTextureTask('texture', 'texture.png');
textureTask.onSuccess = function(task) {
material.diffuseTexture = task.texture;
};
// Load all
assetsManager.onFinish = function(tasks) {
console.log('All assets loaded');
engine.runRenderLoop(() => scene.render());
};
assetsManager.load();
```
### 7. Physics Engine
**Havok Physics Setup**
```javascript
// Import Havok
import HavokPhysics from '@babylonjs/havok';
// Initialize
const havokInstance = await HavokPhysics();
const havokPlugin = new BABYLON.HavokPlugin(true, havokInstance);
// Enable physics
scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), havokPlugin);
// Create physics aggregate for mesh
const sphereAggregate = new BABYLON.PhysicsAggregate(
sphere,
BABYLON.PhysicsShapeType.SPHERE,
{ mass: 1, restitution: 0.75 },
scene
);
// Ground (static)
const groundAggregate = new BABYLON.PhysicsAggregate(
ground,
BABYLON.PhysicsShapeType.BOX,
{ mass: 0 }, // mass 0 = static
scene
);
```
**Physics Shapes**
```javascript
// Available shapes
BABYLON.PhysicsShapeType.SPHERE
BABYLON.PhysicsShapeType.BOX
BABYLON.PhysicsShapeType.CAPSULE
BABYLON.PhysicsShapeType.CYLINDER
BABYLON.PhysicsShapeType.CONVEX_HULL
BABYLON.PhysicsShapeType.MESH
BABYLON.PhysicsShapeType.HEIGHTFIELD
```
**Physics Body Control**
```javascript
// Get body
const body = aggregate.body;
// Apply force
body.applyForce(
new BABYLON.Vector3(0, 10, 0), // force
new BABYLON.Vector3(0, 0, 0) // point of application
);
// Apply impulse
body.applyImpulse(
new BABYLON.Vector3(0, 5, 0),
new BABYLON.Vector3(0, 0, 0)
);
// Set velocity
body.setLinearVelocity(new BABYLON.Vector3(0, 5, 0));
body.setAngularVelocity(new BABYLON.Vector3(0, 1, 0));
// Properties
body.setMassProperties({ mass: 2 });
body.setCollisionCallbackEnabled(true);
```
### 8. Animations
**Direct Animation**
```javascript
// Animate property
BABYLON.Animation.CreateAndStartAnimation(
'anim',
mesh,
'position.y',
30, // FPS
120, // total frames
mesh.position.y, // from
10, // to
BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);
```
**Animation Class**
```javascript
const animation = new BABYLON.Animation(
'myAnimation',
'position.x',
30,
BABYLON.Animation.ANIMATIONTYPE_FLOAT,
BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);
// Keyframes
const keys = [
{ frame: 0, value: 0 },
{ frame: 30, value: 10 },
{ frame: 60, value: 0 }
];
animation.setKeys(keys);
// Attach to mesh
mesh.animations.push(animation);
// Start
scene.beginAnimation(mesh, 0, 60, true);
```
**Animation Groups**
```javascript
const animationGroup = new BABYLON.AnimationGroup('group', scene);
animationGroup.addTargetedAnimation(animation1, mesh1);
animationGroup.addTargetedAnimation(animation2, mesh2);
// Control
animationGroup.play();
animationGroup.pause();
animationGroup.stop();
animationGroup.speedRatio = 2.0;
// Events
animationGroup.onAnimationEndObservable.add(() => {
console.log('Animation complete');
});
```
**Skeleton Animations (from imported models)**
```javascript
// Get skeleton from imported model
const skeleton = result.skeletons[0];
// Get animation ranges
const ranges = skeleton.getAnimationRanges();
// Play animation range
scene.beginAnimation(skeleton, 0, 100, true);
// Or use animation groups
result.animationGroups[0].play();
result.animationGroups[0].setWeightForAllAnimatables(0.5);
```
## Common Patterns
### Pattern 1: Scene Setup with Default Environment
```javascript
const createScene = function() {
const scene = new BABYLON.Scene(engine);
// Quick setup
scene.createDefaultCameraOrLight(true, true, true);
const env = scene.createDefaultEnvironment({
createGround: true,
createSkybox: true,
skyboxSize: 150,
groundSize: 50
});
// Your meshes
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {diameter: 2}, scene);
sphere.position.y = 1;
return scene;
};
```
### Pattern 2: Async Scene Loading
```javascript
const createScene = async function() {
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera('camera', 0, 0, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene);
// Load model
const result = await BABYLON.SceneLoader.ImportMeshAsync(
null,
'https://assets.babylonjs.com/meshes/',
'village.glb',
scene
);
// Setup physics
const havokInstance = await HavokPhysics();
const havokPlugin = new BABYLON.HavokPlugin(true, havokInstance);
scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), havokPlugin);
return scene;
};
createScene().then(scene => {
engine.runRenderLoop(() => scene.render());
});
```
### Pattern 3: Interactive Picking
```javascript
scene.onPointerDown = function(evt, pickResult) {
if (pickResult.hit) {
console.log('Picked mesh:', pickResult.pickedMesh.name);
console.log('Pick point:', pickResult.pickedPoint);
// Highlight picked mesh
pickResult.pickedMesh.material.emissiveColor = new BABYLON.Color3(1, 0, 0);
}
};
// Or use action manager
mesh.actionManager = new BABYLON.ActionManager(scene);
mesh.actionManager.registerAction(
new BABYLON.ExecuteCodeAction(
BABYLON.ActionManager.OnPickTrigger,
function() {
console.log('Mesh clicked');
}
)
);
```
### Pattern 4: Post-Processing Effects
```javascript
// Default pipeline
const pipeline = new BABYLON.DefaultRenderingPipeline('pipeline', true, scene, [camera]);
pipeline.samples = 4;
pipeline.fxaaEnabled = true;
pipeline.bloomEnabled = true;
pipeline.bloomThreshold = 0.8;
pipeline.bloomWeight = 0.5;
pipeline.bloomKernel = 64;
// Depth of field
pipeline.depthOfFieldEnabled = true;
pipeline.depthOfFieldBlurLevel = BABYLON.DepthOfFieldEffectBlurLevel.Low;
pipeline.depthOfField.focusDistance = 2000;
pipeline.depthOfField.focalLength = 50;
// Glow layer
const glowLayer = new BABYLON.GlowLayer('glow', scene);
glowLayer.intensity = 0.5;
// Highlight layer
const highlightLayer = new BABYLON.HighlightLayer('highlight', scene);
highlightLayer.addMesh(mesh, BABYLON.Color3.Green());
```
### Pattern 5: GUI (2D UI)
```javascript
import { AdvancedDynamicTexture, Button, TextBlock, Rectangle } from '@babylonjs/gui';
// Fullscreen UI
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI');
// Button
const button = BABYLON.GUI.Button.CreateSimpleButton('button', 'Click Me');
button.width = '150px';
button.height = '40px';
button.color = 'white';
button.background = 'green';
button.onPointerUpObservable.add(() => {
console.log('Button clicked');
});
advancedTexture.addControl(button);
// Text
const text = new BABYLON.GUI.TextBlock();
text.text = 'Hello World';
text.color = 'white';
text.fontSize = 24;
advancedTexture.addControl(text);
// 3D mesh UI
const plane = BABYLON.MeshBuilder.CreatePlane('plane', {size: 2}, scene);
const advancedTexture3D = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(plane);
const button3D = BABYLON.GUI.Button.CreateSimpleButton('button3D', 'Click Me');
advancedTexture3D.addControl(button3D);
```
### Pattern 6: Shadow Mapping
```javascript
const light = new BABYLON.DirectionalLight('light', new BABYLON.Vector3(-1, -2, -1), scene);
light.position = new BABYLON.Vector3(20, 40, 20);
// Create shadow generator
const shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
shadowGenerator.useExponentialShadowMap = true;
shadowGenerator.usePoissonSampling = true;
// Add shadow casters
shadowGenerator.addShadowCaster(sphere);
shadowGenerator.addShadowCaster(box);
// Enable shadow receiving
ground.receiveShadows = true;
```
### Pattern 7: Particle Systems
```javascript
const particleSystem = new BABYLON.ParticleSystem('particles', 2000, scene);
particleSystem.particleTexture = new BABYLON.Texture('particle.png', scene);
// Emitter
particleSystem.emitter = new BABYLON.Vector3(0, 5, 0);
particleSystem.minEmitBox = new BABYLON.Vector3(-1, 0, 0);
particleSystem.maxEmitBox = new BABYLON.Vector3(1, 0, 0);
// Colors
particleSystem.color1 = new BABYLON.Color4(0.7, 0.8, 1.0, 1.0);
particleSystem.color2 = new BABYLON.Color4(0.2, 0.5, 1.0, 1.0);
particleSystem.colorDead = new BABYLON.Color4(0, 0, 0.2, 0.0);
// Size
particleSystem.minSize = 0.1;
particleSystem.maxSize = 0.5;
// Life time
particleSystem.minLifeTime = 0.3;
particleSystem.maxLifeTime = 1.5;
// Emission rate
particleSystem.emitRate = 1500;
// Direction
particleSystem.direction1 = new BABYLON.Vector3(-1, 8, 1);
particleSystem.direction2 = new BABYLON.Vector3(1, 8, -1);
// Gravity
particleSystem.gravity = new BABYLON.Vector3(0, -9.81, 0);
// Start
particleSystem.start();
```
## Integration Patterns
### Pattern 1: React Integration
```jsx
import { useEffect, useRef } from 'react';
import * as BABYLON from '@babylonjs/core';
function BabylonScene() {
const canvasRef = useRef(null);
const engineRef = useRef(null);
const sceneRef = useRef(null);
useEffect(() => {
if (!canvasRef.current) return;
// Initialize
const engine = new BABYLON.Engine(canvasRef.current, true);
engineRef.current = engine;
const scene = new BABYLON.Scene(engine);
sceneRef.current = scene;
// Setup scene
const camera = new BABYLON.ArcRotateCamera('camera', 0, 0, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvasRef.current, true);
const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene);
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {diameter: 2}, scene);
// Render loop
engine.runRenderLoop(() => {
scene.render();
});
// Resize handler
const handleResize = () => engine.resize();
window.addEventListener('resize', handleResize);
// Cleanup
return () => {
window.removeEventListener('resize', handleResize);
scene.dispose();
engine.dispose();
};
}, []);
return (
<canvas
ref={canvasRef}
style={{ width: '100%', height: '100vh' }}
/>
);
}
```
### Pattern 2: WebXR (VR/AR)
```javascript
const createScene = async function() {
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.FreeCamera('camera', new BABYLON.Vector3(0, 5, -10), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene);
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {diameter: 2}, scene);
sphere.position.y = 1;
const env = scene.createDefaultEnvironment();
// Enable WebXR
const xrHelper = await scene.createDefaultXRExperienceAsync({
floorMeshes: [env.ground],
disableTeleportation: false
});
// XR controller input
xrHelper.input.onControllerAddedObservable.add((controller) => {
controller.onMotionControllerInitObservable.add((motionController) => {
const trigger = motionController.getMainComponent();
trigger.onButtonStateChangedObservable.add(() => {
if (trigger.pressed) {
console.log('Trigger pressed');
}
});
});
});
return scene;
};
```
### Pattern 3: Node Material (Visual Shader Editor)
```javascript
// Create from snippet
const nodeMaterial = await BABYLON.NodeMaterial.ParseFromSnippetAsync('#SNIPPET_ID', scene);
// Apply to mesh
nodeMaterial.build();
mesh.material = nodeMaterial;
// Or create programmatically
const nodeMaterial = new BABYLON.NodeMaterial('node', scene);
const positionInput = new BABYLON.InputBlock('position');
positionInput.setAsAttribute('position');
const worldPos = new BABYLON.TransformBlock('worldPos');
nodeMaterial.addOutputNode(worldPos);
```
## Performance Optimization
### 1. Mesh Optimization
```javascript
// Merge meshes with same material
const merged = BABYLON.Mesh.MergeMeshes(
[mesh1, mesh2, mesh3],
true, // disposeSource
true, // allow32BitsIndices
undefined,
false, // multiMultiMaterials
true // preserveSerializationHelper
);
// Instances (for repeated meshes)
const instance1 = mesh.createInstance('instance1');
const instance2 = mesh.createInstance('instance2');
instance1.position.x = 5;
instance2.position.x = -5;
// Thin instances (even more efficient)
const buffer = new Float32Array(16 * count); // 16 floats per matrix
mesh.thinInstanceSetBuffer('matrix', buffer, 16);
// Freeze meshes (static meshes)
mesh.freezeWorldMatrix();
// Freeze materials
material.freeze();
// Simplify meshes (LOD)
const simplified = mesh.simplify(
[
{ quality: 0.8, distance: 10 },
{ quality: 0.4, distance: 50 },
{ quality: 0.2, distance: 100 }
],
true, // parallelProcessing
BABYLON.SimplificationType.QUADRATIC
);
```
### 2. Scene Optimization
```javascript
// Scene optimizer
const options = new BABYLON.SceneOptimizerOptions();
options.addOptimization(new BABYLON.HardwareScalingOptimization(0, 1));
options.addOptimization(new BABYLON.ShadowsOptimization(1));
options.addOptimization(new BABYLON.PostProcessesOptimization(2));
options.addOptimization(new BABYLON.LensFlaresOptimization(3));
options.addOptimization(new BABYLON.ParticlesOptimization(4));
options.addOptimization(new BABYLON.TextureOptimization(5, 512));
options.addOptimization(new BABYLON.RenderTargetsOptimization(6));
options.addOptimization(new BABYLON.MergeMeshesOptimization(7));
const optimizer = new BABYLON.SceneOptimizer(scene, options);
optimizer.start();
// Octree (spatial partitioning)
const octree = scene.createOrUpdateSelectionOctree();
// Frustum culling
scene.blockMaterialDirtyMechanism = true;
// Skip pointer move picking
scene.skipPointerMovePicking = true;
// Freeze active meshes
scene.freezeActiveMeshes();
```
### 3. Rendering Optimization
```javascript
// Hardware scaling
engine.setHardwareScalingLevel(0.5); // Render at half resolution
// Adaptive quality
scene.onBeforeRenderObservable.add(() => {
const fps = engine.getFps();
if (fps < 30) {
// Reduce quality
engine.setHardwareScalingLevel(2);
} else if (fps > 55) {
// Increase quality
engine.setHardwareScalingLevel(1);
}
});
// Incremental loading
scene.useDelayedTextureLoading = true;
// Culling strategy
mesh.cullingStrategy = BABYLON.AbstractMesh.CULLINGSTRATEGY_BOUNDINGSPHERE_ONLY;
```
### 4. Texture Optimization
```javascript
// Compressed textures
const texture = new BABYLON.Texture('texture.dds', scene);
// Mipmaps
texture.updateSamplingMode(BABYLON.Texture.TRILINEAR_SAMPLINGMODE);
// Anisotropic filtering
texture.anisotropicFilteringLevel = 4;
// KTX2 compression
const texture = new BABYLON.Texture('texture.ktx2', scene);
```
## Common Pitfalls
### Pitfall 1: Memory Leaks
**Problem**: Not disposing resources
```javascript
// ❌ Bad - memory leak
function createAndRemoveMesh() {
const mesh = BABYLON.MeshBuilder.CreateBox('box', {}, scene);
scene.removeMesh(mesh);
}
```
**Solution**: Properly dispose
```javascript
// ✅ Good
function createAndRemoveMesh() {
const mesh = BABYLON.MeshBuilder.CreateBox('box', {}, scene);
mesh.dispose();
}
// Dispose entire scene
scene.dispose();
// Dispose engine
engine.dispose();
```
### Pitfall 2: Performance Issues with Too Many Draw Calls
**Problem**: Each mesh = one draw call
```javascript
// ❌ Bad - 1000 draw calls
for (let i = 0; i < 1000; i++) {
const box = BABYLON.MeshBuilder.CreateBox('box' + i, {}, scene);
box.position.x = i;
}
```
**Solution**: Use instances or merge
```javascript
// ✅ Good - 1 draw call
const box = BABYLON.MeshBuilder.CreateBox('box', {}, scene);
for (let i = 0; i < 1000; i++) {
const instance = box.createInstance('instance' + i);
instance.position.x = i;
}
```
### Pitfall 3: Blocking the Main Thread
**Problem**: Heavy computations blocking render
```javascript
// ❌ Bad - blocks rendering
function createManyMeshes() {
for (let i = 0; i < 10000; i++) {
const mesh = BABYLON.MeshBuilder.CreateSphere('sphere' + i, {}, scene);
}
}
```
**Solution**: Use async/incremental loading
```javascript
// ✅ Good - incremental
async function createManyMeshes() {
for (let i = 0; i < 10000; i++) {
const mesh = BABYLON.MeshBuilder.CreateSphere('sphere' + i, {}, scene);
if (i % 100 === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}
```
### Pitfall 4: Incorrect Camera Controls
**Problem**: Camera not responding
```javascript
// ❌ Bad - forgot attachControl
const camera = new BABYLON.ArcRotateCamera('camera', 0, 0, 10, BABYLON.Vector3.Zero(), scene);
```
**Solution**: Always attach controls
```javascript
// ✅ Good
const camera = new BABYLON.ArcRotateCamera('camera', 0, 0, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
```
### Pitfall 5: Not Handling Async Operations
**Problem**: Using scene before it's ready
```javascript
// ❌ Bad
BABYLON.SceneLoader.ImportMesh('', 'path/', 'model.gltf', scene);
const mesh = scene.getMeshByName('meshName'); // null!
```
**Solution**: Use callbacks or async/await
```javascript
// ✅ Good
const result = await BABYLON.SceneLoader.ImportMeshAsync('', 'path/', 'model.gltf', scene);
const mesh = scene.getMeshByName('meshName');
// Or with callback
BABYLON.SceneLoader.ImportMesh('', 'path/', 'model.gltf', scene, function(meshes) {
const mesh = meshes[0];
});
```
### Pitfall 6: Physics Not Working
**Problem**: Forgot to enable physics or create aggregates
```javascript
// ❌ Bad
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {}, scene);
sphere.physicsImpostor = new BABYLON.PhysicsImpostor(sphere, BABYLON.PhysicsImpostor.SphereImpostor, {mass: 1}, scene);
// Error: Physics not enabled!
```
**Solution**: Enable physics first, use aggregates
```javascript
// ✅ Good
const havokInstance = await HavokPhysics();
const havokPlugin = new BABYLON.HavokPlugin(true, havokInstance);
scene.enablePhysics(new BABYLON.Vector3(0, -9.8, 0), havokPlugin);
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {}, scene);
const aggregate = new BABYLON.PhysicsAggregate(
sphere,
BABYLON.PhysicsShapeType.SPHERE,
{mass: 1},
scene
);
```
## Advanced Topics
### 1. Custom Shaders
```javascript
BABYLON.Effect.ShadersStore['customVertexShader'] = `
precision highp float;
attribute vec3 position;
attribute vec2 uv;
uniform mat4 worldViewProjection;
varying vec2 vUV;
void main(void) {
gl_Position = worldViewProjection * vec4(position, 1.0);
vUV = uv;
}
`;
BABYLON.Effect.ShadersStore['customFragmentShader'] = `
precision highp float;
varying vec2 vUV;
uniform sampler2D textureSampler;
void main(void) {
gl_FragColor = texture2D(textureSampler, vUV);
}
`;
const shaderMaterial = new BABYLON.ShaderMaterial('shader', scene, {
vertex: 'custom',
fragment: 'custom'
}, {
attributes: ['position', 'uv'],
uniforms: ['worldViewProjection']
});
```
### 2. Compute Shaders
```javascript
const computeShader = new BABYLON.ComputeShader('compute', engine, {
computeSource: `
#version 450
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(std430, binding = 0) buffer OutputBuffer { vec4 data[]; } outputBuffer;
void main() {
uint index = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * 8u;
outputBuffer.data[index] = vec4(1.0, 0.0, 0.0, 1.0);
}
`
});
```
### 3. Procedural Textures
```javascript
const noiseTexture = new BABYLON.NoiseProceduralTexture('noise', 256, scene);
noiseTexture.octaves = 4;
noiseTexture.persistence = 0.8;
noiseTexture.animationSpeedFactor = 5;
material.emissiveTexture = noiseTexture;
```
## Debugging
```javascript
// Show inspector
scene.debugLayer.show();
// Show bounding boxes
scene.forceShowBoundingBoxes = true;
// Show wireframes
material.wireframe = true;
// Log FPS
setInterval(() => {
console.log('FPS:', engine.getFps());
}, 1000);
// Instrumentation
const instrumentation = new BABYLON.SceneInstrumentation(scene);
instrumentation.captureFrameTime = true;
console.log('Frame time:', instrumentation.frameTimeCounter.average);
```
## Resources
- [Official Documentation](https://doc.babylonjs.com/)
- [Playground](https://playground.babylonjs.com/)
- [Forum](https://forum.babylonjs.com/)
- [Examples](https://doc.babylonjs.com/examples/)
- [NPM Package](https://www.npmjs.com/package/@babylonjs/core)
## Version Notes
This skill is based on Babylon.js 7.x. For latest features, consult the official documentation.