Search Docs
Loading...
Skip to content

Set Editing Constraints

Control what users can edit in templates by setting fine-grained permissions on individual blocks or globally across your scene using the CE.SDK Scope system.

6 mins
estimated time
GitHub

Editing constraints let you lock specific properties of design elements while keeping others editable. The Scope system provides granular control over more than 20 editing capabilities, including movement, resizing, rotation, fill changes, text editing, and lifecycle operations. Use it to create brand templates, guided editing experiences, and form-based workflows where design integrity must be preserved while still allowing controlled personalization.

Understanding Scopes#

What are Scopes?#

A scope is a permission key that controls a specific editing capability. Each scope represents a distinct action, such as moving blocks ("layer/move"), changing fills ("fill/change"), or editing text content ("text/edit"). By enabling or disabling scopes, you control exactly what users can and cannot do with each design element.

Scopes exist at two levels:

  • Block-level scopes: Per-block permissions set with setScopeEnabled(_:key:enabled:).
  • Global scopes: Default behavior for all blocks set with setGlobalScope(key:value:).

These starting values depend on the editor role, which you set with setRole(_:). Under the default Creator role, every global scope is .allow, so every action is permitted and block-level scopes are not consulted. Blocks created in this role start with their block-level scopes disabled — a setting that only takes effect once a scope defers to the block level, either by switching to the Adopter role (which defers global scopes to the block level) or by deferring individual global scopes yourself, as the rest of this guide does.

Available Scope Categories#

CE.SDK groups scopes into logical categories. Retrieve the full list at runtime with engine.editor.findAllScopes().

CategoryPurposeExample Scopes
Text EditingControl text content and formattingtext/edit, text/character
Fill & StrokeManage colors and gradientsfill/change, fill/changeType, stroke/change
ShapeModify shape propertiesshape/change
Layer TransformControl position and dimensionslayer/move, layer/resize, layer/rotate, layer/flip, layer/crop
Layer AppearanceManage visual propertieslayer/opacity, layer/blendMode, layer/visibility
Effects & FiltersApply visual effectsappearance/adjustments, appearance/filter, appearance/effect, appearance/blur, appearance/shadow
LifecycleControl creation and deletionlifecycle/destroy, lifecycle/duplicate
EditorManage scene-level actionseditor/add, editor/select

Scope Configuration#

Global Scope Modes#

Global scopes set the default behavior for all blocks in the scene. They have three modes:

ModeBehavior
.allowAlways allow the action, overriding block-level settings
.denyAlways deny the action, overriding block-level settings
.deferUse the block-level setting for each block

To make block-level constraints take effect under the default Creator role, defer the relevant global scopes to the block level:

try engine.editor.setGlobalScope(key: "layer/move", value: .defer)
try engine.editor.setGlobalScope(key: "layer/resize", value: .defer)
try engine.editor.setGlobalScope(key: "lifecycle/destroy", value: .defer)
try engine.editor.setGlobalScope(key: "lifecycle/duplicate", value: .defer)

Scope Resolution Priority#

When both global and block-level scopes apply, they resolve in this order:

  1. Global .deny takes highest priority — the action is always denied.
  2. Global .allow takes second priority — the action is always allowed.
  3. Global .defer uses the block-level setting for each block.

Setting Block-Level Constraints#

Locking Position#

Prevent users from moving a block while keeping other edits available:

try engine.block.setScopeEnabled(positionLocked, key: "layer/move", enabled: false)
try engine.block.setScopeEnabled(positionLocked, key: "layer/resize", enabled: true)

Disabling layer/move locks the block’s position. Because deferring a scope makes the engine consult the block-level setting — and block-level scopes start disabled — explicitly enable layer/resize so resizing stays available. Scopes you did not defer (such as fill/change and layer/rotate) remain at their global .allow default and stay editable.

Preventing Deletion#

Protect a block from being deleted or duplicated:

try engine.block.setScopeEnabled(deletionLocked, key: "lifecycle/destroy", enabled: false)
try engine.block.setScopeEnabled(deletionLocked, key: "lifecycle/duplicate", enabled: false)
try engine.block.setScopeEnabled(deletionLocked, key: "layer/move", enabled: true)
try engine.block.setScopeEnabled(deletionLocked, key: "layer/resize", enabled: true)

Disabling lifecycle/destroy and lifecycle/duplicate keeps the block in the template. Enabling layer/move and layer/resize keeps those deferred capabilities available, so the block stays movable and resizable while it cannot be removed. Use this for essential template elements that must remain present.

Checking Scope State#

Query the block-level setting for any scope:

let canMove = try engine.block.isScopeEnabled(positionLocked, key: "layer/move")
print("layer/move enabled at block level: \(canMove)") // false

isScopeEnabled(_:key:) returns whether the scope is enabled at the block level. It does not consider the global scope.

Checking Effective Permissions#

Check the effective permission, which resolves both the block-level and global settings:

let moveAllowed = try engine.block.isAllowedByScope(positionLocked, key: "layer/move")
print("layer/move allowed: \(moveAllowed)") // false

isAllowedByScope(_:key:) returns the final permission after applying the resolution priority above. Use it when you need to know whether an action is actually permitted.

API Reference#

MethodDescription
engine.block.setScopeEnabled(_:key:enabled:)Enable or disable a scope for a specific block
engine.block.isScopeEnabled(_:key:)Check whether a scope is enabled at the block level
engine.block.isAllowedByScope(_:key:)Check whether a scope is allowed, considering both block and global settings
engine.editor.setGlobalScope(key:value:)Set the global scope policy (.allow, .deny, or .defer)
engine.editor.findAllScopes()List all available scope keys