<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">"use strict";(self.webpackChunkapi_stream=self.webpackChunkapi_stream||[]).push([[4443],{3905:function(e,t,a){a.d(t,{Zo:function(){return p},kt:function(){return m}});var n=a(67294);function o(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&amp;&amp;(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t&lt;arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){o(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,o=function(e,t){if(null==e)return{};var a,n,o={},i=Object.keys(e);for(n=0;n&lt;i.length;n++)a=i[n],t.indexOf(a)&gt;=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n&lt;i.length;n++)a=i[n],t.indexOf(a)&gt;=0||Object.prototype.propertyIsEnumerable.call(e,a)&amp;&amp;(o[a]=e[a])}return o}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&amp;&amp;(a="function"==typeof e?e(t):r(r({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(a),m=o,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||i;return a?n.createElement(h,r(r({ref:t},p),{},{components:a})):n.createElement(h,r({ref:t},p))}));function m(e,t){var a=arguments,o=t&amp;&amp;t.mdxType;if("string"==typeof e||o){var i=a.length,r=new Array(i);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&amp;&amp;(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:o,r[1]=s;for(var c=2;c&lt;i;c++)r[c]=a[c];return n.createElement.apply(null,r)}return n.createElement.apply(null,a)}u.displayName="MDXCreateElement"},43368:function(e,t,a){a.r(t),a.d(t,{assets:function(){return p},contentTitle:function(){return l},default:function(){return m},frontMatter:function(){return s},metadata:function(){return c},toc:function(){return d}});var n=a(87462),o=a(63366),i=(a(67294),a(3905)),r=["components"],s={title:"Introduction"},l="Scenes",c={unversionedId:"compositor/scene/basics",id:"compositor/scene/basics",title:"Introduction",description:"The scenes composition mode enables you to create layouts driven directly via the Layout API. RTMP, Webpages, Videos and Images can currently be embedded. For a comprehensive list on all the layer type supported, see the layer types documentation.",source:"@site/docs/compositor/scene/basics.md",sourceDirName:"compositor/scene",slug:"/compositor/scene/basics",permalink:"/docs/compositor/scene/basics",tags:[],version:"current",frontMatter:{title:"Introduction"},sidebar:"mainSidebar",previous:{title:"Scene",permalink:"/docs/category/scene"},next:{title:"Animation",permalink:"/docs/compositor/scene/animation"}},p={},d=[{value:"Scene composition model",id:"scene-composition-model",level:2},{value:"Creating a layout",id:"creating-a-layout",level:2},{value:"Working with Scene composition",id:"working-with-scene-composition",level:2},{value:"Creating layers",id:"creating-layers",level:3},{value:"Switching Layouts",id:"switching-layouts",level:3},{value:"Batch Requests",id:"batch-requests",level:3}],u={toc:d};function m(e){var t=e.components,a=(0,o.Z)(e,r);return(0,i.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"scenes"},"Scenes"),(0,i.kt)("p",null,"The scenes composition mode enables you to create layouts driven directly via the Layout API. RTMP, Webpages, Videos and Images can currently be embedded. For a comprehensive list on all the layer type supported, ",(0,i.kt)("a",{parentName:"p",href:"./types"},"see the layer types documentation"),"."),(0,i.kt)("p",null,"For an end-to-end example of working with scene composition, see the ",(0,i.kt)("a",{parentName:"p",href:"./example-broadcast"},"step-by-step guide")," or view the full ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/golightstream/api.stream-sdk/tree/main/examples/js/scenes"},"example project"),"."),(0,i.kt)("h2",{id:"scene-composition-model"},"Scene composition model"),(0,i.kt)("p",null,'When working with scene composition, a project is created with composition mode "scenes" enabling the ability to render API driven layouts and scene switching.'),(0,i.kt)("p",null,'The project holds the active layout ID, which can be updated during the broadcast. Each layout has a "root" node which holds reference to the child layers to display. The order of layer ids within the ',(0,i.kt)("inlineCode",{parentName:"p"},"children")," property of the root layer is used to infer the stacking order."),(0,i.kt)("img",{src:"https://www.plantuml.com/plantuml/png/ZLAxJWCn4Epz5PQfdVH8GS6q50YA58Z2ZoKSyfrFjW-8elmxVWO7xYGghsPsHhkptZhFhPzwZOnu1-dndT4wl9qPy16TK8KVh4dl4M7SARp1X7CXf5IA18G7mGTWpGzcyf7C5UKaM1G7SfymWhd3kRoDRjcixLyMi3y2aGIj0cmIF1gJ_R4_Z10LDY2_xPjcDj_Sn46Vh_OMO7YXDpKEL6DfkRBS3tV6649ryrQGPaLrHLeGDZVf3iJ8zt0nwsV6uXqcgoFovltehjTh-EBzg64bJR-m-PEPh8JBe5p2ebskLZdnryuwJojvMZHZ_p5p8CsW6ZUK3zR6KdQTOShKAD-Ddf4GsHO65NxpDm00",alt:null}),(0,i.kt)("h2",{id:"creating-a-layout"},"Creating a layout"),(0,i.kt)("p",null,"To enable functionality required for a scene composition, you must define the layout type to be ",(0,i.kt)("inlineCode",{parentName:"p"},"LAYOUT_TYPE_SCENE"),"  when creating it. (note: this cannot be changed later)."),(0,i.kt)("p",null,"Setting the layout type to be ",(0,i.kt)("inlineCode",{parentName:"p"},"LAYOUT_TYPE_SCENE")," will introduce an initial layer of type ",(0,i.kt)("inlineCode",{parentName:"p"},"root")," which all other layers must be a child of (note: the root layer cannot be deleted!). This also enables some guardrails when interacting with the Layout API's layers that would otherwise not be present."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import { ApiStream, LayoutAPIModel } from '@api.stream/sdk';\nconst api = new ApiStream();\n\nconst project = /* your project */;\n\nconst layout = await api.LayoutApi().layout.createLayout({\n    layout: {\n        width: project.rendering?.video?.width,\n        height: project.rendering?.video?.height,\n        collectionId: project.collectionId,\n        projectId: project?.projectId,\n        type: LayoutApiModel.LayoutType.LAYOUT_TYPE_SCENE,\n    }\n});\n")),(0,i.kt)("h2",{id:"working-with-scene-composition"},"Working with Scene composition"),(0,i.kt)("h3",{id:"creating-layers"},"Creating layers"),(0,i.kt)("p",null,"When adding layers, you should reference the ",(0,i.kt)("a",{parentName:"p",href:"./types"},"layer types documentation")," to understand what layers are available and what configuration is possible with them. Any layer created ",(0,i.kt)("em",{parentName:"p"},"must")," be a child of the ",(0,i.kt)("inlineCode",{parentName:"p"},"root")," layer in order to be displayed."),(0,i.kt)("div",{className:"admonition admonition-tip alert alert--success"},(0,i.kt)("div",{parentName:"div",className:"admonition-heading"},(0,i.kt)("h5",{parentName:"div"},(0,i.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,i.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,i.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))),"tip")),(0,i.kt)("div",{parentName:"div",className:"admonition-content"},(0,i.kt)("p",{parentName:"div"},"If updating the active layout in a composition, keep in mind that changes will automatically be reflected in the live composition. Consider using a batch change if you need to modify multiple layers or an entirely different layout with our scene switching API."))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import { ApiStream } from '@api.stream/sdk';\nconst api = new ApiStream();\n\nconst LAYOUT_ID = 'fake-layout-42fa-be5f-addd9d14641e';\n\n// List all existing layers within the layout.\nconst response = await api.LayoutApi().layer.listLayers({ layoutId: layoutId });\n\n// When a layout is created with the \"scene\" type, a layer with type \"root\" will be automatically created. Any \n// layers should be assigned as children to that.\nconst rootLayer = response.layers.find(layer =&gt; layer.type === 'root');\n\nconst layer = await api.LayoutApi().layer.createLayer({\n    layoutId: layoutId,\n    layer: {\n        x: 0,\n        y: 0,\n        width: 1280,\n        height: 720,\n\n        // Layer specific configuration.\n        type: 'webpage',\n        data: {\n            url: 'https://example.org',\n        },\n\n        // This will automatically make this layer the top-most layer.\n        // This can also be done manually by creating a separate update request _or_ a batch request.\n        parentId: rootLayer.id,\n    },\n});\n")),(0,i.kt)("h3",{id:"switching-layouts"},"Switching Layouts"),(0,i.kt)("p",null,"By updating the selected layout ID on a project, you can switch between multiple unique layouts. "),(0,i.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,i.kt)("div",{parentName:"div",className:"admonition-heading"},(0,i.kt)("h5",{parentName:"div"},(0,i.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,i.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,i.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,i.kt)("div",{parentName:"div",className:"admonition-content"},(0,i.kt)("p",{parentName:"div"},"Note: layout switching isn't instantaneous. We make sure the layout is ready and any layers have loaded (images, webpages). There may be a delay while new resources load in (up to a maximum of 5 seconds)"))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import { ApiStream } from '@api.stream/sdk';\nconst api = new ApiStream();\n\nconst COLLECTION_ID = 'fake-collection-4274-8e52-e7edb5b57f8f';\nconst PROJECT_ID = 'fake-project-4988-aab3-8cce055df163';\nconst NEW_LAYOUT_ID = 'fake-layout-42fa-be5f-addd9d14641e';\n\n// Switch scenes\nawait api.LiveApi().project?.updateProject({\n    collectionId: COLLECTION_ID,\n    projectId: PROJECT_ID,\n    composition: {\n        scene: {\n            // highlight-next-line\n            selectedLayoutId: NEW_LAYOUT_ID,\n        },\n    },\n    // highlight-next-line\n    updateMask: { paths: [\"composition.scene.selectedLayoutId\"] },\n});\n")),(0,i.kt)("h3",{id:"batch-requests"},"Batch Requests"),(0,i.kt)("p",null,"Batch requests provide a fast way to setup a large layout without having to fire off multiple API requests. If you're interacting with more than 1 layer, you should use batching."),(0,i.kt)("div",{className:"admonition admonition-tip alert alert--success"},(0,i.kt)("div",{parentName:"div",className:"admonition-heading"},(0,i.kt)("h5",{parentName:"div"},(0,i.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,i.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,i.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))),"tip")),(0,i.kt)("div",{parentName:"div",className:"admonition-content"},(0,i.kt)("p",{parentName:"div"},"When creating a batch request you can self-reference other layers by using the string ",(0,i.kt)("inlineCode",{parentName:"p"},"index:&lt;number&gt;")," in place of the ID. For example, if you create a layer and update another layer referencing it, you can set ",(0,i.kt)("inlineCode",{parentName:"p"},"children")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"['index:0']")))),(0,i.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,i.kt)("div",{parentName:"div",className:"admonition-heading"},(0,i.kt)("h5",{parentName:"div"},(0,i.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,i.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,i.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,i.kt)("div",{parentName:"div",className:"admonition-content"},(0,i.kt)("p",{parentName:"div"},"If you're batch updating a layout in order to completely re-layout the active layout, consider creating a new layout and use layout switching. Layout switching has built-in mechanisms to ensure the full layout is ready before switching, where a simple batch request does not. If you add layers manually, you may see them gradually load in as opposed to clean layout switch."))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-ts"},"import { ApiStream } from '@api.stream/sdk';\nconst api = new ApiStream();\n\nconst LAYOUT_ID = 'fake-layout-42fa-be5f-addd9d14641e';\n\n// Find the root layer.\nconst response = await api.LayoutApi().layer.listLayers({ layoutId: layoutId });\nconst rootLayer = response.layers.find(layer =&gt; layer.type === 'root');\n\nconst layer = await api.LayoutApi().layer.batch({\n    layers: [\n        // Create the a base layer using a web page.\n        { create: { type: 'webpage', width: 1280, height: 720, x: 0, y: 0, data: { url: 'https://example.org' } } },\n        // Create an image layer on top.\n        { create: { type: 'image', height: 60, x: 100, y: 100, data: { media: { url: 'https://api.stream/img/Horizontal-Logo-Primary-Color.svg' } } } },\n\n        // Update the root layer with the layers created.\n        { update: { id: rootLayer.id, children: ['index:0', 'index:1']} },\n    ],\n    layoutId: layoutId,\n});\n")))}m.isMDXComponent=!0}}]);</pre></body></html>