Basic Framework
Creating an Application
First, we need to create an application object.
Note:
Projects using the@zephyr3d/sceneframework must have exactly one application instance!
Once the application is created, you can access the global instance using the getApp function.
import { Application } from '@zephyr3d/scene';
import { backendWebGL2 } from '@zephyr3d/backend-webgl';
// Create an application instance
const myApp = new Application({
// Use WebGL2 as the rendering backend
// Currently supported backends: WebGL, WebGL2, and WebGPU
backend: backendWebGL2,
// Canvas element used for rendering
canvas: document.querySelector('#my-canvas')
});
// Wait for the rendering device to initialize
myApp.ready().then(function () {
// Application is ready, start the render loop
myApp.run();
});The above example shows the most basic application framework. It creates the application, initializes the rendering environment, and starts the main loop.
Since nothing is rendered yet, the window will simply appear black. Let’s add some rendering logic next.
Adding Frame Event Handling
The frame event is triggered once every frame during the render loop.
We can perform scene updates or custom drawing logic within this handler.
// Import Vector4
import { Vector4 } from '@zephyr3d/base';
import { Application } from '@zephyr3d/scene';
import { backendWebGL2 } from '@zephyr3d/backend-webgl';
// Create an application instance
const myApp = new Application({
// Use WebGL2 as the rendering backend
backend: backendWebGL2,
// Canvas element used for rendering
canvas: document.querySelector('#my-canvas')
});
// Wait for the rendering device to be ready
myApp.ready().then(function () {
// Add a frame event handler
myApp.on('tick', function () {
// 'device' is the rendering device.
// clearFrameBuffer clears the screen —
// first argument: RGBA color, second: depth clear value, third: stencil clear value
myApp.device.clearFrameBuffer(new Vector4(0, 1, 0, 1), 1, 0);
});
// Start the render loop
myApp.run();
});Now you should see a green screen.
Handling Input
We can respond to user input by handling events exposed by the application instance.
// Import Vector4
import { Vector4 } from '@zephyr3d/base';
import { Application } from '@zephyr3d/scene';
import { backendWebGL2 } from '@zephyr3d/backend-webgl';
// Create an application instance
const myApp = new Application({
backend: backendWebGL2,
canvas: document.querySelector('#my-canvas')
});
// Wait for the rendering device
myApp.ready().then(function () {
let str = '';
// Set a font for text rendering
myApp.device.setFont('16px arial');
// Frame event handler
myApp.on('tick', function () {
// Clear framebuffer to black
myApp.device.clearFrameBuffer(new Vector4(0, 0, 0, 1), 1, 0);
// Draw text on the screen
myApp.device.drawText(str, 30, 30, '#ffff00');
});
// Pointer move event handler
myApp.on('pointermove', function (ev) {
// Update coordinate text
str = `X:${ev.offsetX.toFixed()} Y:${ev.offsetY.toFixed()}`;
});
// Start render loop
myApp.run();
});The canvas automatically binds the following input events and forwards them through the Application instance:
- pointerdown
- pointerup
- pointermove
- pointercancel
- keydown
- keyup
- keypress
- drag
- dragenter
- dragleave
- dragstart
- dragend
- dragover
- drop
- wheel
- compositionstart
- compositionupdate
- compositionend
In many cases, input events have priority layers — for example, you may want to handle UI events first before passing unhandled inputs to the scene.
For such scenarios, Zephyr3D provides an input middleware system.
You can register multiple middleware functions; they are executed sequentially until one returns true.
If all return false, then event handlers registered via Application.on will be called.
Example:
// Prioritize UI event handling
getInput().use(function (evt, type) {
return processGUIEvent(evt, type);
});
// If UI did not handle the event (processGUIEvent returns false),
// this middleware will handle it
getInput().use(function (evt, type) {
if (type === 'pointerdown') {
onPointerDown();
return true;
} else {
return false;
}
});Rendering a Scene
Now, let’s look at how to render an actual scene.
First, create a Scene object, which serves as a container for renderable elements.
Then, create a camera — either a PerspectiveCamera (for perspective projection) or an OrthoCamera (for orthographic projection).
Finally, use the engine’s setRenderable() method to set the active renderable scene.
import { Application, PerspectiveCamera, Scene } from '@zephyr3d/scene';
import { backendWebGL2 } from '@zephyr3d/backend-webgl';
// Create an application instance
const myApp = new Application({
backend: backendWebGL2,
canvas: document.querySelector('#my-canvas')
});
// Wait for the rendering device
myApp.ready().then(function () {
// Create a scene
const scene = new Scene();
// Create the main camera
scene.mainCamera = new PerspectiveCamera(scene, Math.PI / 3, 1, 100);
// Set the scene as the active renderable for layer 0
getEngine().setRenderable(scene, 0);
// Start the render loop
myApp.run();
});With this code, we render an empty scene. The result should look like this:
Camera Control
We can control the camera by assigning a controller to it.
Currently, Zephyr3D provides two built-in camera controllers:
FPSCameraController
Implements a first-person shooter–style camera control.
Move the camera using W/A/S/D keys, and look around with the mouse.OrbitCameraController
Enables orbiting and zooming around a target point.
Let’s extend the previous example with a camera controller:
import { Application, PerspectiveCamera, OrbitCameraController } from '@zephyr3d/scene';
// ...
// Create the camera
scene.mainCamera = new PerspectiveCamera(scene, Math.PI / 3, 1, 100);
// Add an orbit camera controller
scene.mainCamera.controller = new OrbitCameraController();
// Enable camera controller to receive input by registering it as middleware
getInput().use(scene.mainCamera.handleEvent, scene.mainCamera);
// ...Now, try dragging the left mouse button — you can rotate the camera around the scene’s target point.