Learn how to restrict available fonts to brand typefaces and lock brand elements like logos and legal text, while keeping selected content editable.

Brand guidelines enforcement in CE.SDK combines two complementary approaches:
restricting which assets users can choose and controlling what editing
operations are permitted on brand elements. This guide restricts the available
fonts to an approved set and uses the scopes system to lock brand elements like
logos and legal text so they cannot be modified. On Android, to restrict the
colors users can pick in the editor, configure EditorConfiguration.colorPalette
in your editor configuration. The example builds on a scene with a single page;
adapt the block creation to the scene your app edits.
The snippets below use the Android Engine API directly. If you expose the same workflow through the CE.SDK editor UI, configure its font sheet separately so the visible font families match the approved typeface assets; the Design Editor Starter Kit is a complete Android UI surface you can adapt around this workflow.
Restricting Fonts to Brand Typefaces#
Register the ly.img.typeface asset source with only your approved typefaces
instead of loading the default typeface source, so only brand fonts are
available to choose from. Apply the approved typeface to existing text blocks
before validating or exporting the scene.
// Replace this sample asset URI with your bundled brand font file.val brandRegular = Font( uri = Uri.parse( "file:///android_asset/imgly-assets/ly.img.typeface/fonts/FiraSans/FiraSans-Regular.ttf", ), subFamily = "Regular", weight = FontWeight.NORMAL, style = FontStyle.NORMAL,)val brandTypeface = Typeface(name = "Brand Sans", fonts = listOf(brandRegular))val typefaceSourceId = "ly.img.typeface"val brandTextBlocks = listOf(logoText, legalText, headline)
if (typefaceSourceId in engine.asset.findAllSources()) { engine.asset.removeSource(sourceId = typefaceSourceId)}engine.asset.addLocalSource(sourceId = typefaceSourceId, supportedMimeTypes = emptyList())engine.asset.addAsset( sourceId = typefaceSourceId, asset = AssetDefinition( id = "brand-sans", label = mapOf("en" to "Brand Sans"), payload = AssetPayload(typeface = brandTypeface), ),)engine.asset.assetSourceContentsChanged(sourceId = typefaceSourceId)
brandTextBlocks.forEach { textBlock -> engine.block.setTypeface(block = textBlock, typeface = brandTypeface)}Each Typeface has a display name and a list of Font entries. The sample
uses a bundled Android font asset so the snippet is copy-safe; replace that URI
with a bundled app asset or a self-hosted font file that belongs to your brand.
Setting Global Scopes to Defer#
Scopes control which operations are permitted. Setting a global scope to
GlobalScope.DEFER hands the decision to each block, so per-block settings take
effect.
val brandControlledScopes = listOf( "editor/select", "text/edit", "text/character", "fill/change", "layer/move", "layer/resize", "layer/rotate", "lifecycle/destroy", "lifecycle/duplicate",)
brandControlledScopes.forEach { scope -> engine.editor.setGlobalScope(key = scope, globalScope = GlobalScope.DEFER)}Without this, the global value applies everywhere and block-level settings are ignored.
Creating and Locking Brand Elements#
Create or collect brand blocks such as a logo, wordmark, or legal text, then disable the scopes that must stay protected. The sample uses existing block IDs from its scene setup, but the same calls apply to blocks you create in code.
Locking the Logo and Legal Text#
// Use the IDs of brand blocks that already exist in your scene.val lockedBrandBlocks = listOf(logo, logoText, legalText)lockedBrandBlocks.forEach { brandBlock -> brandControlledScopes.forEach { scope -> engine.block.setScopeEnabled(block = brandBlock, key = scope, enabled = false) }}With these scopes disabled, protected blocks cannot be selected, moved, resized, recolored, edited, duplicated, or deleted.
Creating Editable Content Areas#
While brand elements stay locked, other blocks can remain editable. Enable only the scopes users need on each editable block.
// Use the ID of an editable text block that already exists in your scene.engine.block.setScopeEnabled(block = headline, key = "editor/select", enabled = true)engine.block.setScopeEnabled(block = headline, key = "text/edit", enabled = true)engine.block.setScopeEnabled(block = headline, key = "text/character", enabled = true)engine.block.setScopeEnabled(block = headline, key = "fill/change", enabled = true)engine.block.setScopeEnabled(block = headline, key = "layer/move", enabled = false)engine.block.setScopeEnabled(block = headline, key = "layer/resize", enabled = false)engine.block.setScopeEnabled(block = headline, key = "layer/rotate", enabled = false)engine.block.setScopeEnabled(block = headline, key = "lifecycle/destroy", enabled = false)The sample headline can be selected, edited, restyled, and recolored, but it cannot be moved, resized, rotated, or deleted.
Validating Brand Compliance#
Confirm that the constraints are enforced with
engine.block.isAllowedByScope(), which considers both the global and
block-level scope settings.
val approvedTypefaces = engine.asset.findAssets( sourceId = typefaceSourceId, query = FindAssetsQuery(perPage = 10, page = 0),)val logoCanMove = engine.block.isAllowedByScope(block = logo, key = "layer/move")val logoCanBeDeleted = engine.block.isAllowedByScope(block = logo, key = "lifecycle/destroy")val legalTextCanBeEdited = engine.block.isAllowedByScope(block = legalText, key = "text/edit")val headlineCanBeEdited = engine.block.isAllowedByScope(block = headline, key = "text/edit")val headlineCanChangeTypeface = engine.block.isAllowedByScope(block = headline, key = "text/character")val approvedTypefaceDefinitions = approvedTypefaces.assets.mapNotNull { it.payload.typeface }.toSet()val brandTextUsesApprovedTypeface = brandTextBlocks.all { textBlock -> val typefaces = engine.block.getTypefaces(textBlock) typefaces.isNotEmpty() && typefaces.all { it in approvedTypefaceDefinitions }}
check(approvedTypefaces.assets.size == 1)check(approvedTypefaceDefinitions.size == 1)check(brandTextUsesApprovedTypeface)check(!logoCanMove)check(!logoCanBeDeleted)check(!legalTextCanBeEdited)check(headlineCanBeEdited)check(headlineCanChangeTypeface)Use these checks before saving, exporting, or handing a scene to another surface.
Exporting the Result#
Export the page after configuring the brand rules. Locked blocks remain visible in the final output and render alongside the editable content.
val exportedPng = engine.block.export(block = page, mimeType = MimeType.PNG)Troubleshooting#
- Locked elements still movable: Make sure the global scope is set to
GlobalScope.DEFERbefore changing block-level settings; block-level values are ignored while the global scope allows or denies the operation directly. - Brand elements still editable: Confirm the matching scope, for example
lifecycle/destroy,text/edit,text/character, orfill/change, is disabled on the specific block. - Validation always passes:
isAllowedByScope()reflects the global scope unless it is deferred; verify the global scope before relying on block-level results. - Validation finds unapproved fonts: Apply the approved typeface to existing text blocks before export.
API Reference#
| Method | Category | Purpose |
|---|---|---|
engine.asset.addLocalSource(sourceId=_, supportedMimeTypes=_) |
Asset | Register a local source for approved brand typefaces |
engine.asset.findAllSources() |
Asset | Check whether the typeface source is already registered |
engine.asset.removeSource(sourceId=_) |
Asset | Remove an existing source before registering the approved typeface source |
engine.asset.addAsset(sourceId=_, asset=_) |
Asset | Add a typeface asset to the approved source |
engine.asset.assetSourceContentsChanged(sourceId=_) |
Asset | Notify the engine that the source contents changed |
engine.asset.findAssets(sourceId=_, query=_) |
Asset | Read back approved assets for validation |
engine.block.setTypeface(block=_, typeface=_) |
Text | Apply the approved typeface to text blocks already in the scene |
engine.block.getTypefaces(block=_) |
Text | Validate which typefaces existing text ranges use |
engine.editor.setGlobalScope(key=_, globalScope=_) |
Scope | Defer a scope to block-level settings |
engine.block.setScopeEnabled(block=_, key=_, enabled=_) |
Scope | Enable or disable a scope on one block |
engine.block.isAllowedByScope(block=_, key=_) |
Scope | Check whether an operation is allowed after global and block rules are combined |
engine.block.export(block=_, mimeType=_) |
Block | Export the page with the configured brand elements |
Next Steps#
- Rules Overview — Understand the scopes system fundamentals
- Set Editing Constraints — Configure template editing restrictions
- Color Palette — Customize available colors in the UI