Pages define the format of your designs. Every graphic block, text element, and media asset lives inside a page. This guide shows how pages fit into the Android scene hierarchy, how stacked layouts keep page sizes aligned, and which page-level properties you can configure in Kotlin.
Pages provide the canvas and frame for your designs. Whether you’re building a multi-page document, a carousel, or a video composition, understanding how pages work helps you structure content correctly.
This guide covers:
- Understanding the scene hierarchy: Scene → Pages → Blocks
- Creating and managing multiple pages
- Setting shared page dimensions at the scene level
- Configuring margins, title templates, and page backgrounds
- Finding pages programmatically
Pages in the Scene Hierarchy#
In CE.SDK, content follows a strict hierarchy: a scene contains pages, and pages contain content blocks. Only blocks attached to a page are rendered on the canvas.
// Create a scene with VerticalStack layout for multi-page designs.val scene = engine.scene.create(sceneLayout = SceneLayout.VERTICAL_STACK)
val stack = engine.block.findByType(DesignBlockType.Stack).first()engine.block.setFloat(block = stack, property = "stack/spacing", value = 20F)engine.block.setBoolean( block = stack, property = "stack/spacingInScreenspace", value = true,)When you create a scene with SceneLayout.VERTICAL_STACK, CE.SDK inserts a stack container that arranges pages automatically. Configure the stack before adding pages if you need gaps between them.
val firstPage = engine.block.create(DesignBlockType.Page)engine.block.setWidth(block = firstPage, value = 800F)engine.block.setHeight(block = firstPage, value = 600F)engine.block.appendChild(parent = stack, child = firstPage)
val secondPage = engine.block.create(DesignBlockType.Page)engine.block.setWidth(block = secondPage, value = 800F)engine.block.setHeight(block = secondPage, value = 600F)engine.block.appendChild(parent = stack, child = secondPage)Create pages with engine.block.create(DesignBlockType.Page). In stacked layouts, append pages to the stack container; for single-page or free layouts, you can append a page directly to the scene. Stacked pages should use the same dimensions to avoid normalization when the editor loads the scene.
val imageBlock = engine.block.create(DesignBlockType.Graphic)engine.block.appendChild(parent = firstPage, child = imageBlock)
val rectShape = engine.block.createShape(ShapeType.Rect)engine.block.setShape(block = imageBlock, shape = rectShape)engine.block.setWidth(block = imageBlock, value = 400F)engine.block.setHeight(block = imageBlock, value = 300F)engine.block.setPositionX(block = imageBlock, value = 200F)engine.block.setPositionY(block = imageBlock, value = 150F)
val imageFill = engine.block.createFill(FillType.Image)engine.block.setString( block = imageFill, property = "fill/image/imageFileURI", value = "https://img.ly/static/ubq_samples/sample_1.jpg",)engine.block.setFill(block = imageBlock, fill = imageFill)
val textBlock = engine.block.create(DesignBlockType.Text)engine.block.appendChild(parent = secondPage, child = textBlock)engine.block.replaceText(textBlock, text = "Page 2")engine.block.setTextFontSize(block = textBlock, fontSize = 48F)engine.block.setTextColor( block = textBlock, color = Color.fromRGBA(r = 0.2F, g = 0.2F, b = 0.2F, a = 1F),)engine.block.setWidthMode(block = textBlock, mode = SizeMode.AUTO)engine.block.setHeightMode(block = textBlock, mode = SizeMode.AUTO)
val textWidth = engine.block.getFrameWidth(textBlock)val textHeight = engine.block.getFrameHeight(textBlock)engine.block.setPositionX(block = textBlock, value = (800F - textWidth) / 2F)engine.block.setPositionY(block = textBlock, value = (600F - textHeight) / 2F)Content blocks must be appended to a page before they render. In this example, the first page shows an image block with a rectangular image fill, and the second page centers a text block with auto-sized width and height.
Page Dimensions and Consistency#
The Creative Engine can store pages with different dimensions, but the editor UI is designed around consistent page sizes for stacked layouts such as VERTICAL_STACK and HORIZONTAL_STACK. If you load a stacked scene with mixed page sizes, the editor may normalize the scene to keep the layout predictable.
// Set page dimensions at the scene level so new pages share the same size.engine.block.setFloat( block = scene, property = "scene/pageDimensions/width", value = 800F,)engine.block.setFloat( block = scene, property = "scene/pageDimensions/height", value = 600F,)Use the scene-level properties scene/pageDimensions/width and scene/pageDimensions/height to define the shared default size for pages. The scene/aspectRatioLock property controls whether width and height stay linked when you change one dimension.
Individual pages can also be sized directly with engine.block.setWidth() and engine.block.setHeight(). Keep the scene-level dimensions as the shared default for stacked layouts, and use SceneLayout.FREE when different page sizes are intentional.
Finding and Navigating Pages#
CE.SDK provides several ways to inspect the pages in the current scene.
val allPages = engine.scene.getPages()val currentPage = engine.scene.getCurrentPage()val pagesByType = engine.block.findByType(DesignBlockType.Page)val nearestPages = engine.scene.findNearestToViewPortCenterByType(DesignBlockType.Page)Use these APIs based on your workflow:
engine.scene.getPages()returns all pages in scene order.engine.scene.getCurrentPage()returns the selected page or the page nearest to the viewport center.engine.block.findByType(DesignBlockType.Page)finds every page block regardless of selection state.engine.scene.findNearestToViewPortCenterByType(DesignBlockType.Page)sorts pages by distance to the viewport center.
Page Properties#
Page-specific properties live on the page block itself, not on the scene.
Margins#
Page margins are useful for print and bleed-safe layouts. Enable margins once, then set each side individually.
engine.block.setBoolean( block = firstPage, property = "page/marginEnabled", value = true,)engine.block.setFloat(block = firstPage, property = "page/margin/top", value = 10F)engine.block.setFloat(block = firstPage, property = "page/margin/bottom", value = 10F)engine.block.setFloat(block = firstPage, property = "page/margin/left", value = 10F)engine.block.setFloat(block = firstPage, property = "page/margin/right", value = 10F)Set page/marginEnabled to true, then adjust page/margin/top, page/margin/bottom, page/margin/left, and page/margin/right in design units.
Safety Inset#
The safety inset is the inward inset from the page edge that content must stay inside. It is the counterpart of the bleed margin, which extends outward. Print shops cut with a tolerance, so text and logos placed too close to the edge can be trimmed off.
Set page/safetyEnabled to true, then use page/safetyInset/top, page/safetyInset/bottom, page/safetyInset/left, and page/safetyInset/right to configure each side. Every inset defaults to 0, so set a value as well as enabling the area.
The safety inset is authoring state, and nothing it draws reaches an export.
The guide appears while a drag is in the safety inset or comes near the safety line, and goes away when the drag ends. A move or resize with the arrow keys shows it the same way for 1.6 seconds, without snapping. The engine shades the band between the page edge and the line, draws the line itself, and lets the dragged block snap to it. Set page/safetyRevealDuringTransform to false to draw the guide on every page all the time instead.
Set the guide colors with the page/safetyFillColor and page/safetyFrameColor settings; a fully transparent page/safetyFrameColor hides the line and turns its snapping off.
Exclusion Area#
An exclusion area marks a region of a page that content must stay out of: a window on an envelope, a spine on a book cover, a glue flap on a box, an address panel on a mailer. Where the safety inset is one inset per page, a page can carry any number of exclusion areas, each with its own position, size and rotation.
Create one with the //ly.img.ubq/exclusionArea block type and append it to a page. An exclusion area is a graphic, so it takes a shape, a fill, a stroke and the ordinary transform, and you can put the artwork of the obstruction into it. A new exclusion area is a rectangle with no fill and shows a striped pattern, so it is visible at once. Assign a fill to replace the stripes.
An exclusion area is authoring state. The engine washes it in page/exclusionAreaFillColor and frames it in page/exclusionAreaFrameColor, neither of which reaches an export, and a fully transparent page/exclusionAreaFrameColor hides the frame. An exclusion area is left out of an export as well: set includedInExport to true on the exclusion area to put its artwork in the file.
Set exclusionArea/punchOut to true to cut the exclusion area out of an export instead. The page and everything on it get a hole where the exclusion area is, so a die cut window in the design becomes a window in the file. It is off by default, and the canvas keeps showing the content either way.
Title Template#
The page/titleTemplate property controls the label shown for a page. It supports template tokens such as {{ubq.page_index}} for numbered labels.
engine.block.setString( block = firstPage, property = "page/titleTemplate", value = "Cover",)engine.block.setString( block = secondPage, property = "page/titleTemplate", value = "Content",)The default template is "Page {{ubq.page_index}}". Override it when you want labels such as "Cover" or "Content".
Fill and Background#
Pages support fills through the standard fill API. This example applies a solid background color to a page.
engine.block.setFillSolidColor( block = secondPage, color = Color.fromRGBA(r = 0.95F, g = 0.95F, b = 1F, a = 1F),)Use engine.block.setFillSolidColor(page, color) for a solid page background.
Page Layout Modes#
The scene layout controls how multiple pages are arranged. Use engine.scene.create(sceneLayout = ...) when you create the scene or engine.scene.setLayout(...) later.
| Layout | Description |
|---|---|
SceneLayout.VERTICAL_STACK |
Pages stack vertically from top to bottom. |
SceneLayout.HORIZONTAL_STACK |
Pages arrange side by side from left to right. |
SceneLayout.DEPTH_STACK |
Pages overlap in depth order, which is common for video scenes. |
SceneLayout.FREE |
Pages can be positioned freely and may use different dimensions. |
Pages for Static Designs vs. Video Editing#
Pages behave differently depending on the scene mode you choose.
Static Designs#
For static design scenes, pages act like artboards. Each page is a separate canvas for documents, carousels, social posts, or print layouts, and pages stay spatially arranged according to the scene layout.
Video Editing#
For video scenes, pages represent time-based compositions that play one after another. Page-level playback properties control timeline behavior:
playback/durationdetermines how long each page is shown.playback/timetracks the current playback position.
Troubleshooting#
Content Not Visible#
If a block is not visible, check these common causes:
- Verify the block is attached to a page with
engine.block.appendChild(parent = page, child = block). - For graphic blocks, ensure both a shape and a fill are set.
- Append blocks to the page before setting their size and position.
Dimension Inconsistencies#
If stacked pages show unexpected sizes in the editor, set the shared size on the scene first and keep page dimensions aligned. Use SceneLayout.FREE only when different page sizes are intentional.
Page Not Found#
If engine.scene.getPages() returns an empty list, make sure a scene exists and that you appended at least one page. In headless workflows, you must create both the scene and the pages yourself.
API Reference#
| API | Purpose |
|---|---|
engine.scene.create(sceneLayout=SceneLayout.VERTICAL_STACK) |
Create a multi-page scene with automatic page stacking. |
engine.scene.setLayout(layout=SceneLayout.HORIZONTAL_STACK) |
Change how existing pages are arranged. |
engine.scene.getPages() |
Return all pages in scene order. |
engine.scene.getCurrentPage() |
Return the selected or nearest visible page. |
engine.scene.findNearestToViewPortCenterByType(type=DesignBlockType.Page) |
Sort pages by distance to the viewport center. |
engine.block.findByType(type=DesignBlockType.Page) |
Find all page blocks in the scene. |
engine.block.setFloat(block=_, property="scene/pageDimensions/width", value=_) |
Set the shared page width. |
engine.block.setFloat(block=_, property="scene/pageDimensions/height", value=_) |
Set the shared page height. |
engine.block.setString(block=_, property="page/titleTemplate", value=_) |
Override the displayed page label. |
engine.block.setFillSolidColor(block=_, color=Color.fromRGBA(r=_, g=_, b=_, a=_)) |
Apply a solid background color to a page. |
Next Steps#
- Scenes — Learn about scene structure and management
- Blocks — Understand the building blocks that live inside pages
- Page Format — Configure default page sizes in the UI
- Design Units — Define layout in px, mm, or in—CE.SDK supports unit conversion and DPI scaling for consistent design.
- Templating — Templates enable dynamic, reusable designs with text variables and placeholder media. Learn to create, load, and personalize templates programmatically.