Babylon.js Orbit Camera Showcase — Animated Preset Angles Snippet

Babylon.js Orbit Camera Showcase · Misc · Plain HTML, CSS & JS · Live preview

What's included

Features

Tweened camera presets
Alpha, beta, and radius animate together via BABYLON.Animation instead of snapping instantly.
Ease-in-out motion
A shared CubicEase easing function gives every preset move a cinematic accelerate/decelerate shape.
Live current-value keyframes
Frame 0 always reads the camera's current value, so transitions chain correctly from any state.
Clean tween interruption
scene.stopAnimation cancels in-flight transitions before starting a new one or on manual drag.
Clamped beta range
lowerBetaLimit/upperBetaLimit stop the camera flipping under the ground or to a useless top angle.
Subtle drag inertia
camera.inertia gives manual orbiting a small coast-and-settle rather than an abrupt stop.
Multi-object lineup
Three differently shaped, colored meshes arranged along x form a believable product row.
Active preset indicator
The clicked preset button stays highlighted until manual drag or another preset is chosen.

About this UI Snippet

Babylon.js Orbit Camera Showcase — Tweening a Camera Instead of Snapping It

Screenshot of the Babylon.js Orbit Camera Showcase snippet rendered live

A "view from the top" button that just sets camera.alpha = x; camera.beta = y; directly works, but it looks broken — the camera teleports instantly, which reads as a glitch rather than a deliberate cut. A showcase camera should move the way a cinematographer would move it: smoothly, over a believable duration, with easing. Babylon.js's Animation class is what makes that possible without hand-rolling a tween loop.

Why direct assignment isn't enough

camera.alpha, camera.beta, and camera.radius are just numbers on the camera object — assigning them directly changes the camera's spherical position for the *next rendered frame*, with zero interpolation in between. That's fine for initial setup, wrong for a "go to this preset" button.

Building a per-property Animation

For each of the three properties, this snippet builds a BABYLON.Animation:

var alphaAnim = new BABYLON.Animation('alphaAnim', 'alpha', frameRate, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);

The constructor's second argument, 'alpha', is the literal property name on the target object Babylon will animate — this is why the same Animation class works for meshes, lights, materials, or cameras: it just needs a property name and a target object with that property. setKeys() then defines the keyframes:

alphaAnim.setKeys([{ frame: 0, value: camera.alpha }, { frame: 45, value: target.alpha }]);

Frame 0 is always the camera's current live value, not a hardcoded starting point — this is what makes goToPreset() work correctly no matter where the camera currently is, including mid-transition to a different preset.

Easing, and why CubicEase in EASEINOUT mode

var easing = new BABYLON.CubicEase(); easing.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT); anim.setEasingFunction(easing); — without this, Babylon interpolates keyframes linearly, which looks mechanical for a camera move. Ease-in-out accelerates out of the starting angle and decelerates into the target, the same shape as a real camera operator's move, and is applied identically to all three animated properties so alpha, beta, and radius all arrive with the same timing character.

Running three animations on one target together

camera.animations = [alphaAnim, betaAnim, radiusAnim]; scene.beginAnimation(camera, 0, durationFrames, false, 1); — assigning an array to camera.animations and calling beginAnimation once runs all three simultaneously and in lockstep, since they share the same frame range and frame rate. This is simpler than three separate beginAnimation calls and guarantees they finish at exactly the same frame.

Interrupting an in-flight tween

stopActiveAnims() calls scene.stopAnimation(camera) before starting a new preset transition or the instant the user starts dragging manually. Without this, clicking a second preset mid-tween — or grabbing the camera while it's still animating — would leave two animations racing to control the same alpha/beta/radius values, producing visibly jittery, fighting motion.

Clamped, slightly inertial manual control

camera.lowerBetaLimit/upperBetaLimit stop the user orbiting all the way under the ground plane or to a useless top-down flip. camera.inertia = 0.82 gives manual drags a small coast-and-settle after release — not enough to feel loose, just enough that release doesn't feel like an abrupt stop, echoing the same "nothing in this scene should snap" philosophy as the preset tweens.

Reusing it

This preset-tween pattern applies to any showroom, architectural walkthrough, or configurator that needs "jump to this named view" buttons. Pair it with a Babylon.js Spinning Product Viewer for continuous idle rotation instead of discrete preset stops.

Build with AI

Build, Understand, Optimize, and Extend It With AI

This snippet is a good foundation for exploring Babylon.js's generic Animation system, which works on any object/property pair, not just cameras. Paste it into an AI assistant like Claude and ask it to explain why the Animation constructor takes the property name as a string ('alpha') rather than a direct reference, and what that implies about how Babylon looks up and writes to the target object each frame. Then ask what would happen if durationFrames were set very low (e.g. 5) versus very high (e.g. 300) at the same frameRate, and how that maps to real seconds (durationFrames / frameRate). To extend it: ask it to add a "tour" mode that automatically cycles through all four presets in sequence with a pause between each, add a custom easing function instead of CubicEase for a different feel (BackEase for a slight overshoot, BounceEase for a playful settle), or animate a light's intensity alongside the camera move so each preset also has its own lighting mood.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a 3D showcase scene with animated camera preset buttons using Babylon.js (from a CDN, global namespace BABYLON) in plain HTML, CSS, and JavaScript with a single <canvas> element.

Requirements:
- Initialize a BABYLON.Engine and Scene, and an ArcRotateCamera with attachControl enabled for manual drag-to-orbit, with lowerRadiusLimit/upperRadiusLimit and lowerBetaLimit/upperBetaLimit all set to sane clamped ranges, plus a moderate camera.inertia value so releasing a drag coasts slightly instead of stopping dead.
- Add a ground plane and at least three differently shaped primitive meshes (e.g. box, cylinder, sphere) arranged in a row along the x-axis at different positions, each with a distinct StandardMaterial color, to form a small "product lineup".
- Add basic lighting (a HemisphericLight plus at least one PointLight).
- Define at least 4 named camera presets as plain objects specifying target alpha, beta, and radius values.
- Implement a goToPreset(name) function that builds a BABYLON.Animation for each of alpha, beta, and radius, with frame 0 set to the camera's CURRENT live value (not a hardcoded start) and the final frame set to the preset's target value. Apply a BABYLON.CubicEase with EASINGMODE_EASEINOUT to each animation. Assign all three animations to camera.animations and start them together with a single scene.beginAnimation call so they animate in lockstep over the same duration -- the camera must visibly tween to the preset, never snap instantly.
- Before starting a new preset animation, call scene.stopAnimation(camera) to cancel any animation already in progress, so rapid preset switching or manual dragging never fights an in-flight tween.
- Add a pointerdown listener on the canvas that also stops any active preset animation, so starting a manual drag immediately hands control back to the user.
- Render four preset buttons below the canvas; highlight whichever was most recently clicked, and clear the highlight when the user drags manually.
- Style it as a dark themed panel with the canvas as the focal element and pill-shaped preset buttons below it.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

Requires
<div class="boc-stage">
  <div class="boc-head">
    <span class="boc-tag">Babylon.js · animated camera presets</span>
    <h2>Product Lineup</h2>
    <p>Drag to orbit freely, or jump to a preset angle — the camera tweens there, it never snaps.</p>
  </div>
  <canvas id="bocCanvas"></canvas>
  <div class="boc-presets">
    <button class="boc-btn" data-view="front">Front</button>
    <button class="boc-btn" data-view="top">Top</button>
    <button class="boc-btn" data-view="side">Side</button>
    <button class="boc-btn" data-view="hero">Hero angle</button>
  </div>
</div>

Step by step

How to Use

  1. 1
    Add the Babylon.js CDNInclude the babylon.js UMD build for the global BABYLON namespace.
  2. 2
    Paste HTML, CSS, and JSA three-object product lineup renders on a ground plane with an orbit camera.
  3. 3
    Drag to orbit freelyattachControl handles manual rotation with a touch of inertia via camera.inertia.
  4. 4
    Click a preset buttonFront, Top, Side, and Hero angle each tween the camera there over 45 frames with easing.
  5. 5
    Click a preset mid-tweenThe in-flight animation is stopped and a new one starts cleanly from the current position.
  6. 6
    Drag manually mid-tweenStarting a drag cancels the active preset animation so it never fights your input.

Real-world uses

Common Use Cases

Virtual showrooms
Product lineups with named camera angles a customer can jump between.
Architectural or interior walkthroughs
Named preset views (entry, top-down, elevation) for a 3D space.
Configurator step transitions
Camera moves that accompany configuration steps in a product customizer.
Learning Babylon.js Animation
A clear reference for tweening arbitrary properties, not just meshes.
Portfolio showcase scenes
A polished way to present a 3D asset collection with guided viewpoints.
Camera choreography prototyping
A base to extend into scripted multi-shot camera sequences.

Got questions?

Frequently Asked Questions

Setting them directly changes the camera position instantly on the next render, with no interpolation -- the camera would teleport to the new angle, which looks like a glitch rather than a deliberate transition. Wrapping each property in a BABYLON.Animation and calling scene.beginAnimation() interpolates smoothly across a chosen number of frames instead.

Each Animation's first keyframe (frame 0) is set to the camera's current live value -- camera.alpha, camera.beta, camera.radius -- read at the moment the button is clicked, not a hardcoded prior position. That guarantees the tween always starts from wherever the camera actually is.

goToPreset() calls stopActiveAnims(), which calls scene.stopAnimation(camera) before building the new animations. That cancels whatever transition was still running so the new one starts cleanly from the camera's current (mid-transition) position, rather than the two animations fighting to control the same properties.

Linear interpolation between keyframes moves at a constant angular speed the entire transition, which feels mechanical for a camera move. Ease-in-out accelerates away from the start and decelerates into the end, matching how a real camera operator would perform the same move, and it is applied identically to alpha, beta, and radius so all three arrive with matching timing.

beta is the vertical polar angle of the orbit. Without limits, dragging far enough would let the camera orbit underneath the ground plane or flip to a disorienting straight-down angle. Clamping beta to a sensible range keeps every manually reachable angle looking intentional.

Set up the engine, scene, camera, meshes, and preset definitions once inside a useEffect (React) or onMounted (Vue), and expose a goToPreset function via a ref or emitted event that UI buttons call -- the animation logic itself needs no changes since it operates directly on the camera instance, not component state.