Search Docs
Loading...
Skip to content

Architecture

Understand how CE.SDK is structured around the CreativeEngine and its six interconnected APIs.

6 mins
estimated time
GitHub

CE.SDK is built around the CreativeEngine runtime, exposed on Android through the Engine class. It manages state, rendering, and coordination between six specialized APIs. Understanding how these pieces connect makes it much easier to navigate the SDK and decide where a change belongs.

The CreativeEngine#

The Engine is the central coordinator. Creating content, manipulating blocks, rendering, and exporting all flow through it. Start it once, keep engine work on the main thread, and access the rest of CE.SDK through its API namespaces.

The Engine manages:

  • One active scene containing all design content
  • Six API namespaces for different domains of functionality
  • Event dispatching for reactive state management
  • Resource loading and caching
  • Rendering to a SurfaceView, TextureView, or offscreen context

On Android, lifecycle methods such as start, bindSurfaceView, bindTextureView, and bindOffscreen are annotated @MainThread. Engine-only integrations therefore typically run inside CoroutineScope(Dispatchers.Main).launch { ... }.

Core APIs#

The engine exposes six API namespaces, each handling a specific domain of functionality:

// The engine exposes six API namespaces:
engine.scene // Scene API — content hierarchy
engine.block // Block API — create and modify blocks
engine.asset // Asset API — manage asset sources
engine.editor // Editor API — edit modes, undo/redo, roles
engine.event // Event API — subscribe to changes
engine.variable // Variable API — template variables
APINamespacePurpose
Scene APIengine.sceneContent hierarchy: create, load, and save scenes
Block APIengine.blockCreate, modify, and query design blocks
Asset APIengine.assetRegister and query asset sources
Editor APIengine.editorEdit modes, undo/redo, and user roles
Event APIengine.eventSubscribe to engine state changes
Variable APIengine.variableTemplate variables for data-driven designs

Content Hierarchy#

CE.SDK organizes content in a tree: ScenePagesBlocks.

  • Scene: The root container. One scene per engine instance. Supports both static designs and time-based video editing.
  • Pages: Containers within a scene. Artboards in design scenes and timeline compositions in video scenes.
  • Blocks: The atomic units: graphics, text, audio, video, and more. Everything visible is a block.

Create a scene, add a page, and populate it with blocks:

// Create a scene with a page and a graphic block.
val scene = engine.scene.create()
val page = engine.block.create(DesignBlockType.Page)
engine.block.appendChild(parent = scene, child = page)
val block = engine.block.create(DesignBlockType.Graphic)
engine.block.setShape(block, shape = engine.block.createShape(ShapeType.Rect))
engine.block.setFill(block, fill = engine.block.createFill(FillType.Color))
engine.block.appendChild(parent = page, child = block)
// Traverse the hierarchy.
val pages = engine.scene.getPages()
val children = engine.block.getChildren(block = pages.first())

The Scene API manages this hierarchy. The Block API manipulates individual blocks within it. See Scenes and Blocks for details.

Scene Contexts#

CE.SDK uses the same scene hierarchy for static designs and time-based content. Starter kits and editor configurations decide which editing tools are available for a given experience; the scene itself still contains pages and blocks.

// Scenes use the same hierarchy for static and time-based experiences.
val contentScene = engine.scene.create()
val contentPage = engine.block.create(DesignBlockType.Page)
engine.block.appendChild(parent = contentScene, child = contentPage)
  • Design experiences: Static outputs such as social posts, print materials, and graphics. Blocks are positioned spatially on pages.
  • Video experiences: Time-based outputs with playback, timeline, and audio support. Blocks can use temporal properties such as duration and trim.

Create the scene with engine.scene.create(), then configure the editor experience or automation pipeline around the content you want to produce. See Scenes for details.

Event System#

Subscribe to engine events to build reactive UIs that update when state changes. On Android, the Event API exposes a Kotlin Flow of DesignBlockEvent batches:

// Subscribe to block changes using Flow.
subscription =
engine.event.subscribe(blocks = listOf(scene))
.onEach { events ->
events.forEach { event ->
println("Block ${event.block} had event: ${event.type}")
}
}
// `this` is the CoroutineScope from the surrounding launch block.
.launchIn(this)

Store the Job returned by launchIn and cancel it when you no longer need updates.

See Events for details on subscribing to engine state changes.

Template Variables#

The Variable API enables data-driven designs. Define variables at the scene level and reference them in text blocks with {{variableName}} syntax:

// Set and retrieve template variables.
engine.variable.set(key = "username", value = "Jane")
val username = engine.variable.get(key = "username")

When variable values change, affected blocks update automatically.

How They Connect#

A typical flow shows the interconnection:

  1. Scene API creates the content structure.
  2. Asset API provides images, templates, or other content.
  3. Block API creates blocks and applies assets to them.
  4. Variable API injects dynamic data into text blocks.
  5. Editor API controls what users can modify.
  6. Event API notifies your UI of every change.

Each API focuses on one domain, but they operate through the same Engine instance. The runtime coordinates these interactions for you.

Integration Patterns#

CE.SDK runs in two main Android contexts:

  • Interactive UI: Use the Editor composable directly or start from one of the Android starter kits. This gives you a ready-made editing surface while still exposing the same Engine APIs underneath. The legacy solution composables such as DesignEditor are deprecated in favor of this architecture.
  • Headless: Create the engine yourself with Engine.getInstance(...), call start(...), and render through bindOffscreen(...). Use this for exports, automation, and batch processing. See Headless Mode.

Both patterns use the same six APIs. The difference is how you host the engine and whether you attach a UI render target.

Next Steps#