Using Layouts
Display and position media sources in layouts behind or above your module
A module runs in a full-screen portrait view on the device with your web page covering the entire screen. You may optionally choose to add camera capture and video playback components in predetermined layout locations. These components render behind your web page by default, so any part of your webpage that is not transparent will be visible over top of them.
To accommodate devices with notched displays, be aware of safe areas for rendering non-background elements.
Layout Creator

Creating Layouts
To add components within a layout, use the LayoutManager.createLayout() function.
You'll need to use a LayoutCustomConfig object to define your own layout. You also need to pass in a O3hMediaSource for each element id in the layout.
The promise of this call will resolve once the layout is loaded and ready to be shown. When you call Layout.show() on the object returned by the promise, the layout will become visible and replace a previously visible layout.
import * as o3h from "/api/o3h.js";
const runtime = o3h.Instance;
// Global variables
let layout;
let cameraMediaSource;
// Module functions
async function setupModule() {
// Get the runtime managers
const mediaSourceManager = runtime.getMediaSourceManager();
const layoutManager = runtime.getLayoutManager();
// Create a camera media source
cameraMediaSource = await mediaSourceManager.createCameraSource();
// Creating a full-screen camera layout
const layoutConfig = {"id": "main"};
const mediaSources = {"main": cameraMediaSource};
layout = await layoutManager.createLayout(layoutConfig, mediaSources);
}
async function startModule() {
// Wait for the camera to start before showing the layout
await cameraMediaSource.startCamera();
// Show the layout when the loading screen is removed
await layout.show();
}
// Setup module then display the module to the player
setupModule().then(() => runtime.ready(startModule));
Custom Layouts
A layout is defined by a nested structure of LayoutCustomConfig elements each containing zero or more child elements.
Layout elements are positioned either using flex or float layout logic.
Flex Layout
If the parent element has a childrenFlexDirection property then any children that have a flexRatio will be arranged side by side within the parent element with their relative size determined by their flex ratios proportion.
Example: The "Top Horizontal Split with Primary on Bottom" layout
{
childrenFlexDirection: o3h.Layout.Direction.Vertical,
children: [
{
flexRatio: 1,
childrenFlexDirection: o3h.Layout.Direction.Horizontal,
children: [
{
id: 'topleft',
flexRatio: 1
},
{
id: 'topright',
flexRatio: 1
}
]
},
{
id: 'bottom',
flexRatio: 2,
}
]
}
Float Layout
If a layout element defines anchor and not flexRatio then it will ignore any childrenFlexDirection from the parent and instead will be positioned based on the now required pivot, offset, and size properties.
Example: The "Vertical even split with lower PIP" layout
{
childrenFlexDirection: o3h.Layout.Direction.Vertical,
children: [
{
id: 'top',
flexRatio: 1
},
{
flexRatio: 1,
children: [
{
id: 'bottom',
flexRatio: 1
},
{
id: 'pip',
anchor: o3h.Layout.Position.TopLeft,
pivot: o3h.Layout.Position.TopLeft,
offset: {
x: 0.1,
y: -0.1
},
size: {
x: 0.25,
y: 0.25
}
}
]
}
]
}
Components
A component is a fixed sized and positioned rectangular portion of the screen, designed to display the content of a media source. Components can be independently scaled, masked, tinted, rotated and more!
You can get a reference to the component object using its element id from the layout object via Layout.getComponent().
Updated almost 2 years ago