
Babylonjs Engine
- 1.5k installs
- 629 repo stars
- Updated November 20, 2025
- freshtechbro/claudedesignskills
babylonjs-engine is a skill for Babylon.js 3D web rendering with scenes, cameras, PBR, physics, and model loading.
About
The babylonjs-engine skill supports comprehensive Babylon.js 3D web rendering for games, visualizations, and immersive applications as an alternative to Three.js with built-in editor integration. Core setup creates Engine on canvas, Scene with optional geometry maps for large mesh counts, render loop, and resize handlers. ES6 TypeScript imports cover Engine, Scene, FreeCamera, Vector3, HemisphericLight, and CreateSphere mesh creation. Camera systems include FreeCamera FPS movement with WASD keys, ArcRotateCamera orbit controls, and UniversalCamera combinations. Lighting spans HemisphericLight, DirectionalLight, PointLight, and SpotLight with shadow generators. PBR materials use PBRMaterial with metallic roughness workflow, environment textures, and clear coat options. Mesh loading imports GLTF, OBJ, and STL via SceneLoader AppendAsync patterns. Physics integrates CannonJS or Havok plugin with impostors and collision events. Animation uses Animation class keyframes or animation groups from imported assets. Post-processing adds default pipeline bloom, depth of field, and motion blur. WebGPU engine option available for next-gen rendering.
- Engine, Scene, camera, lighting, and mesh creation initialization patterns.
- TypeScript ES6 imports from @babylonjs/core module paths.
- PBR materials with environment maps and clear coat support.
- GLTF and OBJ loading via SceneLoader with async AppendAsync.
- Physics plugins, animation keyframes, and post-process pipelines included.
Babylonjs Engine by the numbers
- 1,479 all-time installs (skills.sh)
- +103 installs in the week ending Jul 29, 2026 (Skillselion tracking)
- Ranked #23 of 247 Game Development skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 31, 2026 (Skillselion catalog sync)
babylonjs-engine capabilities & compatibility
- Capabilities
- engine and scene setup · camera and lighting systems · pbr material workflow · asset loading patterns · physics and post processing
- Use cases
- frontend
What babylonjs-engine says it does
Comprehensive skill for Babylon.js 3D web rendering engine.
const engine = new Engine(canvas);
npx skills add https://github.com/freshtechbro/claudedesignskills --skill babylonjs-engineAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.5k |
|---|---|
| repo stars | ★ 629 |
| Security audit | 2 / 3 scanners passed |
| Last updated | November 20, 2025 |
| Repository | freshtechbro/claudedesignskills ↗ |
How do I build a real-time 3D browser experience with Babylon.js cameras, lights, and GLTF models?
Build real-time 3D web experiences with Babylon.js scenes, cameras, physics, PBR materials, and model loading.
Who is it for?
Developers building browser 3D games, visualizations, or immersive web apps with Babylon.js.
Skip if: Skip for pure 2D CSS UI without any 3D canvas requirements.
When should I use this skill?
User works on Babylon.js, 3D scenes, WebGL rendering, PBR materials, or model loading.
What you get
Configured Babylon scene with render loop, materials, optional physics, and loaded assets.
- Production-oriented Babylon.js scene code
- Pattern-mapped 3D feature implementations
By the numbers
- Organized into 10 major Babylon.js topic sections
Files
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
// 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
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
const scene = new BABYLON.Scene(engine, {
// Optimize for large mesh counts
useGeometryUniqueIdsMap: true,
useMaterialMeshMap: true,
useClonedMeshMap: true
});2. Camera Systems
Free Camera (FPS-style)
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]; // DArc Rotate Camera (Orbit)
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)
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)
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)
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)
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)
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)
// Only affect specific meshes
light.includedOnlyMeshes = [mesh1, mesh2, mesh3];
// Or exclude specific meshes
light.excludedMeshes = [mesh4, mesh5];4. Mesh Creation
Built-in Shapes
// 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
// 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
// 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
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)
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
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
// 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)
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
// 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
// Available shapes
BABYLON.PhysicsShapeType.SPHERE
BABYLON.PhysicsShapeType.BOX
BABYLON.PhysicsShapeType.CAPSULE
BABYLON.PhysicsShapeType.CYLINDER
BABYLON.PhysicsShapeType.CONVEX_HULL
BABYLON.PhysicsShapeType.MESH
BABYLON.PhysicsShapeType.HEIGHTFIELDPhysics Body Control
// 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
// 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
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
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)
// 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
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
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
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
// 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)
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
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
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
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)
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)
// 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
// 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
// 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
// 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
// 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
// ❌ Bad - memory leak
function createAndRemoveMesh() {
const mesh = BABYLON.MeshBuilder.CreateBox('box', {}, scene);
scene.removeMesh(mesh);
}Solution: Properly dispose
// ✅ 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
// ❌ 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
// ✅ 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
// ❌ 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
// ✅ 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
// ❌ Bad - forgot attachControl
const camera = new BABYLON.ArcRotateCamera('camera', 0, 0, 10, BABYLON.Vector3.Zero(), scene);Solution: Always attach controls
// ✅ 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
// ❌ Bad
BABYLON.SceneLoader.ImportMesh('', 'path/', 'model.gltf', scene);
const mesh = scene.getMeshByName('meshName'); // null!Solution: Use callbacks or async/await
// ✅ 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
// ❌ 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
// ✅ 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
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
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
const noiseTexture = new BABYLON.NoiseProceduralTexture('noise', 256, scene);
noiseTexture.octaves = 4;
noiseTexture.persistence = 0.8;
noiseTexture.animationSpeedFactor = 5;
material.emissiveTexture = noiseTexture;Debugging
// 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
Version Notes
This skill is based on Babylon.js 7.x. For latest features, consult the official documentation.
Babylon.js Real-World Examples
Comprehensive collection of production-ready Babylon.js patterns and implementations.
Table of Contents
- Model Loading & Optimization
- Advanced Materials
- Physics Simulations
- Particle Systems
- Post-Processing Effects
- GUI & User Interface
- WebXR & VR
- Performance Optimization
- Camera Systems
- Animation Patterns
---
Model Loading & Optimization
GLTF Model Viewer with Progress
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)
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
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
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
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
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
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)
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
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
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
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
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
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
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)
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
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
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
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
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
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
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
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
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
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)
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.
<!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>
{
"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"
}
}
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
npm install
# or
yarn
# or
pnpm installDevelopment
npm run devOpens at http://localhost:3000
Build
npm run buildPreview Production Build
npm run previewProject Structure
starter_babylon/
├── index.html # Entry HTML
├── package.json # Dependencies
├── vite.config.js # Vite configuration
└── src/
├── main.js # Main application
└── style.css # StylesWhat'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)
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)
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:
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
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
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
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
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
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
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)
const env = scene.createDefaultEnvironment();
const xr = await scene.createDefaultXRExperienceAsync({
floorMeshes: [env.ground]
});Add Particles
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
License
MIT - Free for personal and commercial use
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();
}
});
});
}
});
* {
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;
}
}
import { defineConfig } from 'vite';
export default defineConfig({
server: {
port: 3000,
open: true
},
build: {
target: 'esnext',
minify: 'terser'
},
optimizeDeps: {
exclude: ['@babylonjs/havok']
}
});
Babylon.js API Reference
Complete API reference for Babylon.js 7.x covering core classes, methods, and properties.
Table of Contents
---
Engine
BABYLON.Engine
Main rendering engine that manages the WebGL context and rendering loop.
Constructor
new Engine(
canvasOrContext: HTMLCanvasElement | WebGLRenderingContext,
antialias?: boolean,
options?: EngineOptions,
adaptToDeviceRatio?: boolean
): EngineParameters:
canvasOrContext: HTML canvas element or WebGL contextantialias: Enable anti-aliasing (default: false)options: Engine configuration optionsadaptToDeviceRatio: Adapt to device pixel ratio (default: false)
EngineOptions:
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
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 recoveryMethods
Rendering
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): voidFrame Info
engine.getFps(): number
engine.getDeltaTime(): number // Milliseconds since last frame
engine.getTimeStep(): number // Time step in msState Management
engine.wipeCaches(bruteForce?: boolean): void
engine.dispose(): void
engine.clear(color: Color4, backBuffer: boolean, depth: boolean, stencil?: boolean): voidScreenshots
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
new Scene(
engine: Engine,
options?: SceneOptions
): SceneSceneOptions:
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
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 nodesRendering
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 colorOptimization
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 cullingAnimation
scene.animationsEnabled: boolean // Enable animations
scene.useConstantAnimationDeltaTime: boolean // Fixed timestep
scene.constantlyUpdateMeshUnderPointer: boolean // Continuous pickingMethods
Rendering
scene.render(updateCameras?: boolean, ignoreAnimations?: boolean): void
scene.enableDepthRenderer(camera?: Camera, useFloat?: boolean): DepthRenderer
scene.enableGeometryBufferRenderer(ratio?: number): GeometryBufferRendererMesh Management
scene.getMeshByName(name: string): AbstractMesh | null
scene.getMeshById(id: string): AbstractMesh | null
scene.getMeshesByTags(tagsQuery: string): Mesh[]
scene.removeMesh(mesh: AbstractMesh): numberCamera Management
scene.getCameraByName(name: string): Camera | null
scene.getCameraById(id: string): Camera | null
scene.removeCamera(camera: Camera): numberLight Management
scene.getLightByName(name: string): Light | null
scene.getLightById(id: string): Light | null
scene.removeLight(light: Light): numberMaterial Management
scene.getMaterialByName(name: string): Material | null
scene.getMaterialById(id: string): Material | null
scene.removeMaterial(material: Material): numberAnimation
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 | nullPicking
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
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 | nullOptimization
scene.createOrUpdateSelectionOctree(
maxCapacity?: number,
maxDepth?: number
): Octree<AbstractMesh>
scene.freezeActiveMeshes(frustumCullingEnabled?: boolean): Scene
scene.unfreezeActiveMeshes(): SceneCleanup
scene.dispose(): void
scene.disposeSounds(): voidEvents (Observables)
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
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.
new FreeCamera(
name: string,
position: Vector3,
scene: Scene
): FreeCameraProperties:
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:
camera.attachControl(noPreventDefault?: boolean): void
camera.detachControl(): void
camera.setTarget(target: Vector3): voidBABYLON.ArcRotateCamera
Orbital camera that rotates around a target.
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
): ArcRotateCameraProperties:
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 sensitivityMethods:
camera.setPosition(position: Vector3): void
camera.setTarget(target: Vector3): void
camera.focusOn(meshesOrMinMaxVectorAndDistance: any, doNotUpdateMaxZ?: boolean): void
camera.zoomOn(meshes?: AbstractMesh[], doNotUpdateMaxZ?: boolean): voidBABYLON.UniversalCamera
Combination of FreeCamera and TouchCamera.
new UniversalCamera(
name: string,
position: Vector3,
scene: Scene
): UniversalCameraInherits all FreeCamera properties and adds touch support.
BABYLON.FollowCamera
Camera that follows a target mesh.
new FollowCamera(
name: string,
position: Vector3,
scene: Scene
): FollowCameraProperties:
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
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.
new HemisphericLight(
name: string,
direction: Vector3,
scene: Scene
): HemisphericLightProperties:
light.groundColor: Color3 // Color from below
light.direction: Vector3 // Light directionBABYLON.DirectionalLight
Parallel light (sun-like).
new DirectionalLight(
name: string,
direction: Vector3,
scene: Scene
): DirectionalLightProperties:
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 bottomBABYLON.PointLight
Omni-directional point light.
new PointLight(
name: string,
position: Vector3,
scene: Scene
): PointLightProperties:
light.position: Vector3 // Light position
light.shadowMinZ: number // Shadow near plane
light.shadowMaxZ: number // Shadow far planeBABYLON.SpotLight
Focused cone light.
new SpotLight(
name: string,
position: Vector3,
direction: Vector3,
angle: number,
exponent: number,
scene: Scene
): SpotLightProperties:
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
new Mesh(
name: string,
scene: Scene | null,
parent?: Node,
source?: Mesh,
doNotCloneChildren?: boolean,
clonePhysicsImpostor?: boolean
): MeshProperties
Transform
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
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 boundsRendering
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 progressCollisions
mesh.checkCollisions: boolean // Enable collision detection
mesh.ellipsoid: Vector3 // Collision shape
mesh.ellipsoidOffset: Vector3 // Collision offsetLOD
mesh.useLODScreenCoverage: boolean // Use screen coverage for LODMethods
Transform
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): MeshGeometry
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(): numberCloning
mesh.clone(name: string, newParent?: Node | null, doNotCloneChildren?: boolean): Mesh
mesh.createInstance(name: string): InstancedMeshLOD
mesh.addLODLevel(distanceOrScreenCoverage: number, mesh: Mesh | null): Mesh
mesh.removeLODLevel(mesh: Mesh): Mesh
mesh.getLODLevelAtDistance(distance: number): Mesh | nullOptimization
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(): MeshDisposal
mesh.dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): voidMeshBuilder
Static class for creating built-in shapes.
// 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
new StandardMaterial(
name: string,
scene: Scene
): StandardMaterialProperties
Colors
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
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 mapRendering
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
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 sourceFresnel
material.diffuseFresnelParameters: FresnelParameters | null
material.opacityFresnelParameters: FresnelParameters | null
material.reflectionFresnelParameters: FresnelParameters | null
material.emissiveFresnelParameters: FresnelParameters | null
material.refractionFresnelParameters: FresnelParameters | nullMethods
material.clone(name: string): StandardMaterial
material.dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void
material.freeze(): void
material.unfreeze(): void
material.needAlphaBlending(): boolean
material.needAlphaTesting(): booleanBABYLON.PBRMaterial
Physically based rendering material.
Constructor
new PBRMaterial(
name: string,
scene: Scene
): PBRMaterialProperties
Metallic-Roughness Workflow
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 baseTextureSpecular-Glossiness Workflow
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: booleanOther Maps
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 mapEnvironment
material.environmentTexture: BaseTexture | null // IBL/reflection
material.environmentIntensity: number // Environment strength
material.useRadianceOverAlpha: boolean // Refl over alpha
material.useSpecularOverAlpha: boolean // Spec over alphaRendering
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 aboveAdvanced
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
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
): TextureProperties
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 loadedMethods
texture.clone(): Texture
texture.dispose(): void
texture.updateURL(url: string, buffer?: string | ArrayBuffer | ArrayBufferView | HTMLImageElement | Blob, onLoad?: () => void): void
texture.updateSamplingMode(samplingMode: number): voidBABYLON.CubeTexture
Cubemap texture for reflections/environment.
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): CubeTextureBABYLON.RenderTargetTexture
Render-to-texture for effects.
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
): RenderTargetTextureProperties:
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
// 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).
new PhysicsAggregate(
transformNode: TransformNode,
type: PhysicsShapeType,
options?: PhysicsAggregateParameters,
scene?: Scene
): PhysicsAggregatePhysicsShapeType:
BABYLON.PhysicsShapeType.SPHERE
BABYLON.PhysicsShapeType.BOX
BABYLON.PhysicsShapeType.CAPSULE
BABYLON.PhysicsShapeType.CYLINDER
BABYLON.PhysicsShapeType.CONVEX_HULL
BABYLON.PhysicsShapeType.MESH
BABYLON.PhysicsShapeType.HEIGHTFIELD
BABYLON.PhysicsShapeType.CONTAINERPhysicsAggregateParameters:
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:
aggregate.body: PhysicsBody // Physics body
aggregate.shape: PhysicsShape // Collision shape
aggregate.transformNode: TransformNode // Associated nodeMethods:
aggregate.dispose(): voidBABYLON.PhysicsBody
Physics body control.
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): voidBABYLON.PhysicsRaycastResult
Raycast result.
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
new Animation(
name: string,
targetProperty: string,
framePerSecond: number,
dataType: number,
loopMode?: number,
enableBlending?: boolean
): AnimationData Types:
Animation.ANIMATIONTYPE_FLOAT
Animation.ANIMATIONTYPE_VECTOR2
Animation.ANIMATIONTYPE_VECTOR3
Animation.ANIMATIONTYPE_QUATERNION
Animation.ANIMATIONTYPE_MATRIX
Animation.ANIMATIONTYPE_COLOR3
Animation.ANIMATIONTYPE_COLOR4
Animation.ANIMATIONTYPE_SIZELoop Modes:
Animation.ANIMATIONLOOPMODE_RELATIVE // Continue from current
Animation.ANIMATIONLOOPMODE_CYCLE // Loop
Animation.ANIMATIONLOOPMODE_CONSTANT // Stop at end
Animation.ANIMATIONLOOPMODE_YOYO // Ping-pongMethods
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
): AnimatableBABYLON.AnimationGroup
Group of synchronized animations.
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.
// 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
// 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.
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
// 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_MODEMaterial Constants
// 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/
Related skills
How it compares
Use for Babylon.js-specific production snippets; use generic frontend-design skills for standard 2D web UI without WebGL scenes.
FAQ
How is the render loop started?
engine.runRenderLoop calling scene.render each frame.
Can TypeScript ES modules be used?
Yes; import from @babylonjs/core subpaths like Engines and scene.
What formats load meshes?
GLTF, OBJ, STL via SceneLoader AppendAsync patterns.
Is Babylonjs Engine safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.