Controls the availability of features within the Creative Editor SDK.
The FeatureAPI allows you to enable or disable specific functionality within the editor based on custom conditions or user permissions.
Understanding the Feature System#
The feature system uses a predicate chain to determine if a feature is enabled. There are two types of predicates:
- Boolean predicates (e.g.,
trueorfalse) - These are always terminal and immediately return their value. - Function predicates - The implementation decides whether to call
isPreviousEnable()(continue chain) or return directly (end chain).
Evaluation Order#
Predicates are evaluated in this order:
set()predicates (most recent first) - Evaluated FIRSTenable()/disable()state - Evaluated LAST
This means set() can override enable() and disable().
Common Use Cases and Expected Outcomes#
Use Case 1: Simple Enable/Disable#
// Enable a feature with its default behaviorcesdk.feature.enable('ly.img.delete');// isEnabled: true
// Disable itcesdk.feature.disable('ly.img.delete');// isEnabled: false
// Re-enable itcesdk.feature.enable('ly.img.delete');// isEnabled: trueExpected outcome: enable() and disable() work together to toggle features on/off.
Use Case 2: Custom Conditions with set()#
set()#// Enable delete only when something is selectedcesdk.feature.set('ly.img.delete', ({ engine }) => { return engine.block.findAllSelected().length > 0;});// isEnabled: depends on selection
// Now calling disable() won't work because set() is evaluated first!cesdk.feature.disable('ly.img.delete');// isEnabled: still depends on selection (disable is ignored)Expected outcome: set() function predicates are evaluated before disable(),
so disable() has no effect when a set() predicate exists.
Use Case 3: Terminal Boolean Predicates#
cesdk.feature.enable('ly.img.delete'); // Default predicate: truecesdk.feature.set('ly.img.delete', false); // Adds false to front// Chain: [set(false), enable(true)]// Evaluation: false (stops here, never reaches enable)// isEnabled: false
cesdk.feature.set('ly.img.delete', true); // Adds true to front// Chain: [set(true), set(false), enable(true)]// Evaluation: true (stops here, never reaches the rest)// isEnabled: trueExpected outcome: The most recent set() call with a boolean wins because
boolean predicates are terminal.
Use Case 4: Layering Conditions with Functions#
// Base: Feature enabled by defaultcesdk.feature.enable('ly.img.delete');
// Layer 1: Add selection requirementcesdk.feature.set('ly.img.delete', ({ isPreviousEnable, engine }) => { const baseEnabled = isPreviousEnable(); // Checks enable(true) const hasSelection = engine.block.findAllSelected().length > 0; return baseEnabled && hasSelection;});// isEnabled: true only if enabled AND has selection
// Layer 2: Add mode requirementcesdk.feature.set('ly.img.delete', ({ isPreviousEnable, engine }) => { const previousEnabled = isPreviousEnable(); // Checks Layer 1 const isDesignMode = engine.scene.getMode() === 'Design'; return previousEnabled && isDesignMode;});// isEnabled: true only if all conditions met (mode + selection + enabled)Expected outcome: Each set() call with a function can build on previous
conditions by calling isPreviousEnable().
Use Case 5: Overriding with set()#
set()#cesdk.feature.enable('ly.img.delete');cesdk.feature.disable('ly.img.delete');// isEnabled: false (disable overrides enable)
// But set() overrides both:cesdk.feature.set('ly.img.delete', true);// Chain: [set(true), disable(false)]// isEnabled: true (set is terminal, disable never evaluated)Expected outcome: set() with a boolean always wins because it’s evaluated
first and is terminal.
Use Case 6: Glob Patterns for Bulk Operations#
// Enable all video features at oncecesdk.feature.enable('ly.img.video.*');
// Disable all crop featurescesdk.feature.disable('ly.img.crop.*');
// Set custom predicate for all navigation featurescesdk.feature.set('ly.img.navigation.*', ({ engine }) => { return engine.scene.getMode() === 'Design';});
// Check if all video features are enabledconst allVideoEnabled = cesdk.feature.isEnabled('ly.img.video.*');// Returns true only if ALL matching features are enabledExpected outcome: Glob patterns match multiple features. isEnabled() with
a glob returns true only if all matching features are enabled.
Use Case 7: Role-Based Access Control#
const userRole = 'editor'; // Could be 'viewer', 'editor', 'admin'
cesdk.feature.set('ly.img.delete', () => { return userRole === 'editor' || userRole === 'admin';});
cesdk.feature.set('ly.img.settings', () => { return userRole === 'admin';});Expected outcome: Features are enabled based on user roles, with predicates evaluated on every check.
Key Principles#
- Use
enable()for simple on/off - Works with default predicates - Use
disable()to turn off enabled features - Only works if noset()predicates exist - Use
set()for custom logic - Overridesenable()/disable() - Boolean predicates are terminal - Stop evaluation immediately
- Function predicates can chain - Call
isPreviousEnable()to continue - Most recent
set()wins - Evaluated in LIFO order (most recent first) - Glob patterns affect multiple features - Use
*as wildcard
Constructors#
Constructor#
FeatureAPI
FeatureAPIFeature Control#
Methods for enabling and checking the status of editor features based on custom predicates.
enable()#
Enables one or more features using their default predicates.
This is the recommended way to enable features. Each feature has a sensible
default predicate that determines when it should be available in the UI.
To customize the behavior, use the set() method instead.
Supports glob patterns (e.g., ‘ly.img.video.*’) to enable multiple features at once.
Use * as a wildcard to match any sequence of characters.
Parameters#
| Parameter | Type | Description |
|---|---|---|
featureId | FeatureId |
Returns#
void
Examples#
Enable single feature with its default predicate:
cesdk.feature.enable('ly.img.delete');Enable multiple features at once:
cesdk.feature.enable(['ly.img.delete', 'ly.img.duplicate']);Enable all video features using a glob pattern:
cesdk.feature.enable('ly.img.video.*');Enable all navigation features:
cesdk.feature.enable('ly.img.navigation.*');Call Signature#
enable(featureId, predicate): void;Parameters#
| Parameter | Type | Description |
|---|---|---|
featureId | FeatureId | |
predicate | FeaturePredicate | The condition that determines if the feature is enabled. |
Returns#
void
Deprecated#
Use cesdk.feature.set(featureId, predicate) instead.
This overload will be removed in a future version.
Enables one or more features based on the provided predicate.
Signatures#
enable(featureId: FeatureId | FeatureId[]): voidenable(featureId: FeatureId | FeatureId[], predicate: FeaturePredicate): voiddisable()#
Disables one or more features.
This is a convenience method that adds a false predicate to the feature’s
predicate chain, effectively disabling the feature. Disabled features will
not be shown in the UI.
Supports glob patterns (e.g., ‘ly.img.video.*’) to disable multiple features at once.
Use * as a wildcard to match any sequence of characters.
Parameters#
| Parameter | Type | Description |
|---|---|---|
featureId | FeatureId |
Returns#
void
Examples#
Disable a single feature:
cesdk.feature.disable('ly.img.delete');Disable multiple features at once:
cesdk.feature.disable([ 'ly.img.delete', 'ly.img.duplicate', 'ly.img.group']);Disable all video features using a glob pattern:
cesdk.feature.disable('ly.img.video.*');Disable all crop features:
cesdk.feature.disable('ly.img.crop.*');Signature#
disable(featureId: FeatureId | FeatureId[]): voidset()#
Sets a feature’s enabled state, replacing any existing predicates.
This method provides a unified way to enable or disable features. When setting
to true, the feature’s default predicate is used. When setting to false,
the feature is explicitly disabled. You can also provide a custom predicate
function for advanced control.
Supports glob patterns (e.g., ‘ly.img.video.*’) to set multiple features at once.
Use * as a wildcard to match any sequence of characters.
Parameters#
| Parameter | Type | Description |
|---|---|---|
featureId | FeatureId | The feature ID or glob pattern to set. |
enabled | FeaturePredicate | Boolean to enable/disable, or a predicate function for custom logic. |
Returns#
void
Examples#
Enable a feature using its default predicate:
cesdk.feature.set('ly.img.delete', true);Disable a feature:
cesdk.feature.set('ly.img.delete', false);Set a feature with a custom predicate:
cesdk.feature.set('ly.img.delete', ({ engine }) => { return engine.block.findAllSelected().length > 0;});Disable all video features using a glob pattern:
cesdk.feature.set('ly.img.video.*', false);Enable all filter features with a custom predicate:
cesdk.feature.set('ly.img.filter.*', ({ engine }) => { // Only enable filters for images const selected = engine.block.findAllSelected(); return selected.some(id => engine.block.getType(id) === '//ly.img.ubq/graphic');});Signature#
set(featureId: FeatureId, enabled: FeaturePredicate): voidlist()#
Lists all registered feature IDs, optionally filtered by a pattern.
This method is useful for debugging and discovering which features are currently registered in the editor. You can provide a glob-style pattern to filter the results.
Parameters#
| Parameter | Type | Description |
|---|---|---|
options? | { matcher?: string; } | Optional configuration object with a matcher property for glob-style pattern filtering (e.g., ‘ly.img.video.*’). |
options.matcher? | string | - |
Returns#
An array of feature IDs sorted alphabetically.
Examples#
List all registered features:
const allFeatures = cesdk.feature.list();console.log(allFeatures); // ['ly.img.delete', 'ly.img.duplicate', ...]List features matching a pattern:
const videoFeatures = cesdk.feature.list({ matcher: 'ly.img.video.*' });console.log(videoFeatures); // ['ly.img.video.timeline', 'ly.img.video.clips', ...]List navigation features:
const navFeatures = cesdk.feature.list({ matcher: 'ly.img.navigation.*' });Signature#
list(options?: object): FeatureId[]get()#
Gets the predicate chain for a specific feature.
This method returns the array of predicates currently registered for a feature,
allowing you to inspect the feature’s configuration. Returns undefined if the
feature is not registered.
Parameters#
| Parameter | Type | Description |
|---|---|---|
featureId | FeatureId | The feature ID to query. |
Returns#
The array of predicates for the feature, or undefined if not registered.
Examples#
Get predicates for a feature:
const predicates = cesdk.feature.get('ly.img.delete');if (predicates) { console.log(`Feature has ${predicates.length} predicates`);}Check if a feature is registered:
const isRegistered = cesdk.feature.get('ly.img.delete') !== undefined;Signature#
get(featureId: FeatureId): FeaturePredicate[]isEnabled()#
Checks if one or more features are currently enabled.
Supports glob patterns (e.g., ‘ly.img.video.*’) to check multiple features at once.
When a glob pattern is used, returns true only if all matching features are enabled.
Parameters#
| Parameter | Type | Description |
|---|---|---|
featureId | FeatureId | The feature ID or glob pattern to check. |
context? | IsEnabledFeatureContext | The context object containing a reference to the underlying engine. |
Returns#
boolean
True if the feature (or all matching features for glob patterns) is enabled, false otherwise.
Examples#
Check if a single feature is enabled:
const isDeleteEnabled = cesdk.feature.isEnabled('ly.img.delete');Check if all video features are enabled:
const allVideoFeaturesEnabled = cesdk.feature.isEnabled('ly.img.video.*');Check with custom context (useful in predicates):
cesdk.feature.set('ly.img.delete', ({ engine }) => { return cesdk.feature.isEnabled('ly.img.duplicate', { engine });});Signature#
isEnabled(featureId: FeatureId, context?: IsEnabledFeatureContext): boolean