Search Docs
Loading...
Skip to content

Enforce Brand Guidelines

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

A branded Android export with locked logo and editable headline content

8 mins
estimated time
GitHub

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.

// 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.DEFER before 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, or fill/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#