Overview
Nosmai supports visual content through encrypted .nosmai packages. Every package declares one of four types:
filtereffectbeauty_effectbackground
The type tells the SDK what the package does and which active position it occupies.
The application does not need to select that position manually. It passes the package path to applyEffect(path). Nosmai reads the package type and applies it correctly.
The simplest rule is:
List a package
|
v
Obtain its local path
|
v
Call applyEffect(path)
|
v
Read the active state
The four package types
Filter
A filter changes the overall appearance of the camera image.
Common examples:
- color grading
- LUT filters
- brightness or tone styles stored in a package
- black-and-white looks
- cinematic color styles
- full-frame shader effects
- screen overlays that do not need face tracking
A filter normally affects the full camera frame. It usually does not need to follow a face.
Only one external filter package is active at a time. Applying another filter replaces the previous filter.
A filter can normally remain active with:
- one
effectorbeauty_effect - one
background - built-in beauty and makeup
Example:
Warm color filter
+
Face glasses effect
+
Background replacement
These can be visible together because they have different responsibilities.
Effect
An effect adds an interactive or tracked visual experience.
Common examples:
- face masks
- glasses
- hats
- 2D face overlays
- 3D models
- animated face effects
- face mesh effects
- screen distortion
- animated particles
- effects that react to face movement
An effect may use face tracking, animation, a 3D model, a full-frame shader, or background processing. Its exact requirements are stored inside the package.
Only one external face effect is active at a time.
effect and beauty_effect share the same active position. Therefore:
- applying an
effectreplaces the currentbeauty_effect - applying a
beauty_effectreplaces the currenteffect
This replacement is intentional. It prevents two face packages from competing for the same tracked face resources.
Beauty effect
A beauty_effect is a packaged beauty or makeup look.
Common examples:
- a complete makeup preset
- packaged lipstick and blusher
- packaged eye makeup
- a face-mesh beauty look
- a beauty look containing textures and authored strengths
- a coordinated makeup style distributed as one
.nosmaifile
A beauty_effect is different from a normal effect because its catalog category is beauty. Applications can display it in a dedicated Beauty section.
It is also different from built-in beauty.
| Packaged beauty effect | Built-in beauty |
|---|---|
Stored in a .nosmai package | Compiled into the SDK |
| Listed with local or cloud packages | Controlled through direct methods |
Applied with applyEffect(path) | Applied with methods such as applySkinSmoothing or applyLipstick |
| Has package metadata and preview | Uses application-defined controls |
Occupies the same position as an effect | Managed through built-in beauty controls |
The package type must be exactly:
beauty_effect
Do not use beauty, beauty-effect, or a display label inside the package manifest.
Only one effect or beauty_effect package can be active at the same time.
Background
A background package changes or replaces the area behind the subject.
Common examples:
- background blur
- an authored image background
- an animated background
- a virtual room
- a background shader
- a packaged background replacement
A background package is different from a manual background configured with a direct API.
| Background package | Manual background |
|---|---|
Distributed as a .nosmai file | Created by the application |
Listed as type background | Not part of the package catalog |
Applied with applyEffect(path) | Applied with background configuration methods |
| Contains authored package settings | Uses color, image, video, or blur values supplied by the app |
Only one external background package is active at a time. Applying another background package replaces the previous one.
Type comparison
| Type | Main purpose | Usually tracks a face | Replacement rule |
|---|---|---|---|
filter | Full-frame color or visual style | No | Replaces the previous filter |
effect | AR, tracked, animated, or interactive effect | Often | Replaces the current effect or beauty_effect |
beauty_effect | Packaged makeup or beauty look | Yes | Replaces the current effect or beauty_effect |
background | Packaged background visual | No, but may identify the subject | Replaces the previous background |
What can be active together
The package type controls replacement.
| Active combination | Result |
|---|---|
filter and effect | Both can remain active |
filter and beauty_effect | Both can remain active |
filter and background | Both can remain active |
beauty_effect and background | Both can remain active |
effect and beauty_effect | The latest package replaces the previous one |
built-in beauty, makeup, reshape, color, or hair and effect | The latest mode clears the other mode |
built-in beauty, makeup, reshape, color, or hair and beauty_effect | The latest mode clears the other mode |
built-in controls and a regular external filter | Both can remain active |
two filter packages | The latest filter replaces the previous filter |
two background packages | The latest background replaces the previous background |
Some effects include their own background or explicitly control background behavior. In that case, the effect package decides whether another background can remain active.
The application should not manually remove the previous package before applying another package of the same type. Applying the new package already performs the replacement.
When a user switches between an AR-slot package and built-in beauty, update the interface from the apply completion and active-state listener. The SDK performs the required clear automatically in both directions.
Package type and source are different
Do not confuse package type with package source.
Package type describes what the package does:
filter effect beauty_effect background
Package source describes where the application obtained it:
local cloud debug
For example:
- a local
filter - a cloud
filter - a local
beauty_effect - a cloud
beauty_effect
Local and cloud copies use the same apply method after a local file path is available.
Built-in features are not .nosmai packages
Built-in features use direct SDK methods.
Examples:
- skin smoothing
- skin whitening
- lipstick
- eyeshadow
- blusher
- eyelash
- eyebrow
- face slimming
- eye enlargement
- nose slimming
- brightness
- contrast
- sharpening
- white balance
These features are not returned by the local or cloud .nosmai package lists.
For example, Flutter built-in beauty is applied directly:
await NosmaiFlutter.instance.applySkinSmoothing(0.35); await NosmaiFlutter.instance.setFaceSlimLevel(0.15);
A packaged beauty preset is applied by path:
await NosmaiFlutter.instance.applyEffect( beautyPackage.path, );
Package manifest type
Every .nosmai package contains an internal manifest. The canonical field is type.
Example:
{
"type": "beauty_effect",
"schemaVersion": "2.0"
}
Use one exact value:
filter effect beauty_effect background
The filename does not decide the type. A file named cinematic_beauty.nosmai is not a beauty effect unless its internal manifest declares beauty_effect.
The application should not open, decrypt, or edit the package. Nosmai validates and reads it when needed.
Local production packages
A production local entry contains:
<name>.nosmai <name>_manifest.json <name>_preview.png
The external manifest supplies catalog information that can be read without opening the encrypted package:
{
"id": "soft_glam",
"displayName": "Soft Glam",
"description": "A balanced makeup look",
"type": "beauty_effect",
"version": "1.0",
"author": "Nosmai"
}
The external type should match the internal package type.
Recommended Flutter layout:
assets/
nosmai_filters/
soft_glam/
soft_glam.nosmai
soft_glam_manifest.json
soft_glam_preview.png
Recommended Android layout:
app/src/main/assets/
Nosmai_Filters/
soft_glam/
soft_glam.nosmai
soft_glam_manifest.json
soft_glam_preview.png
Recommended iOS layout:
nosmai_filters/
soft_glam/
soft_glam.nosmai
soft_glam_manifest.json
soft_glam_preview.png
An incomplete production entry may be skipped. Keep the package, external manifest, and preview together.
List local packages
Flutter
Get all local packages grouped by type:
final groups =
await NosmaiFlutter.instance.getAllLocalFilters();
final filters = groups['filter'] ?? const [];
final effects = groups['effect'] ?? const [];
final beautyEffects =
groups['beauty_effect'] ?? const [];
final backgrounds =
groups['background'] ?? const [];
Get one local type:
final filters =
await NosmaiFlutter.instance.getLocalFilters();
final effects =
await NosmaiFlutter.instance.getLocalEffects();
final beautyEffects =
await NosmaiFlutter.instance.getLocalBeautyEffects();
final backgrounds =
await NosmaiFlutter.instance.getLocalBackgrounds();
getLocalFilters() returns the production local catalog. Use the typed methods when the interface shows separate tabs.
Android
Get every local package:
List<NosmaiFilterInfo> packages =
NosmaiEffects.getFilters();
Get one type:
List<NosmaiFilterInfo> effects =
NosmaiEffects.getFilters(
NosmaiFilterInfo.Type.EFFECT
);
Android types are:
FILTER EFFECT BEAUTY_EFFECT BACKGROUND
iOS
Get every local package:
NosmaiSDK *sdk = [NosmaiSDK sharedInstance];
NSArray<NosmaiFilterInfo *> *packages =
[sdk getFilters];
Get one type:
NSArray<NosmaiFilterInfo *> *beautyEffects =
[sdk getFiltersOfType:
NosmaiFilterTypeBeautyEffect];
iOS types are:
NosmaiFilterTypeFilter NosmaiFilterTypeEffect NosmaiFilterTypeBeautyEffect NosmaiFilterTypeBackground
Debug package discovery
Debug discovery is for development and testing.
It can find loose .nosmai files that do not yet have a complete production manifest and preview.
Do not use the debug method as the production catalog.
Flutter
Get every debug package:
final packages =
await NosmaiFlutter.instance.getDebugFilters();
Get one debug type:
final effects =
await NosmaiFlutter.instance.getDebugFilters(
type: NosmaiLocalFilterType.effect,
);
Available Flutter debug types are:
NosmaiLocalFilterType.filter NosmaiLocalFilterType.effect NosmaiLocalFilterType.beautyEffect NosmaiLocalFilterType.background
Android
NosmaiEffects.getDebugFilters(
NosmaiFilterInfo.Type.EFFECT,
(filters, error) -> {
if (error != null) {
return;
}
// Update the development filter list.
}
);
iOS
[sdk getDebugFiltersOfType:
NosmaiFilterTypeEffect
completion:^(
NSArray<NosmaiFilterInfo *> *filters,
NSError *error
) {
if (error != nil) {
return;
}
// Update the development filter list.
}];
Debug discovery may take longer than production listing because missing catalog metadata can require the SDK to inspect the package.
Apply any package
Use one apply method for all four package types.
Flutter
final success =
await NosmaiFlutter.instance.applyEffect(
selected.path,
);
if (!success) {
// Keep the previous selected state.
}
Android
NosmaiEffects.applyEffect(
selected,
new NosmaiEffects.EffectCallback() {
@Override
public void onSuccess() {
// The package is active.
}
@Override
public void onError(String message) {
// Keep the previous selected state.
}
}
);
A path can also be applied:
NosmaiEffects.applyEffect(
selected.getPath(),
callback
);
iOS
[sdk applyEffectInfo:selected
completion:^(
BOOL success,
NSError *error
) {
if (!success) {
// Keep the previous selected state.
return;
}
// The package is active.
}];
The apply operation is asynchronous. Do not mark the package selected before the success result.
Why the method is named applyEffect
applyEffect is the unified package method. Its name does not mean that it only accepts a package whose type is effect.
It accepts:
filtereffectbeauty_effectbackground
Flutter also keeps applyFilter(path) as a compatibility alias. New code should use applyEffect(path) for every .nosmai package.
Active selection state
The application should use SDK state to keep selected cells, check marks, and active labels correct.
A reliable screen flow is:
- subscribe to active-state changes
- read the current state once
- build selected UI from that state
- update the UI after future state changes
- cancel the subscription when the screen closes
Do not keep a separate list of assumed active packages. A new package can replace an older package automatically.
Flutter
Read the initial state:
final initial =
await NosmaiFlutter.instance.getActiveEffects();
Listen for changes:
late final StreamSubscription<NosmaiActiveEffects>
activeEffectsSubscription;
void observeActiveEffects() {
activeEffectsSubscription =
NosmaiFlutter.instance
.onActiveEffectsChanged
.listen((state) {
final hasFilter = state.hasFilter;
final hasEffect = state.hasEffect;
final hasBeautyEffect =
state.hasBeautyEffectPackage;
final hasBackground =
state.hasBackgroundPackage;
final filterPath =
state.activeFilterPath;
final effectPath =
state.activeEffectPath;
final backgroundPath =
state.activeBackgroundPath;
// Update selected cells from these values.
});
}
Cancel when the owner closes:
await activeEffectsSubscription.cancel();
The active face package appears in activeEffectPath. Its metadata tells the application whether it is an effect or a beauty_effect.
Typed convenience methods are also available:
final activeFilter =
await NosmaiFlutter.instance.getActiveFilterInfo();
final activeEffect =
await NosmaiFlutter.instance.getActiveEffectInfo();
final activeBeauty =
await NosmaiFlutter.instance
.getActiveBeautyEffectInfo();
Android
Keep the listener instance so it can be removed:
private final
NosmaiEffectsEngine.PipelineStateListener
activeStateListener =
state -> updateSelectedItems(state);
@Override
protected void onStart() {
super.onStart();
NosmaiEffects.addPipelineStateListener(
activeStateListener
);
updateSelectedItems(
NosmaiEffects.getCurrentPipelineState()
);
}
@Override
protected void onStop() {
NosmaiEffects.removePipelineStateListener(
activeStateListener
);
super.onStop();
}
Do not register an anonymous listener that cannot be removed later.
iOS
Use the effects delegate:
@interface CameraViewController ()
<NosmaiEffectsDelegate>
@end
- (void)viewDidLoad {
[super viewDidLoad];
[NosmaiCore shared].effects.delegate = self;
}
- (void)nosmaiEffectsDidChangePipelineState:
(NosmaiPipelineState *)state {
[self updateSelectedItems:state];
}
- (void)dealloc {
if ([NosmaiCore shared].effects.delegate == self) {
[NosmaiCore shared].effects.delegate = nil;
}
}
Read the current state when the screen first opens:
NosmaiPipelineState *state =
[[NosmaiSDK sharedInstance]
currentPipelineState];
Remove packages
Remove the position that the user intends to clear.
Flutter
await NosmaiFlutter.instance.clearFilter();
This clears the external filter.
await NosmaiFlutter.instance.clearAREffect();
This clears the active effect or beauty_effect.
Remove a selected item by its type:
await NosmaiFlutter.instance.removeEffect( selected, );
Remove all external packages:
await NosmaiFlutter.instance.removeAllFilters();
Clear external packages and other active visual state:
await NosmaiFlutter.instance.clearAll();
Android
NosmaiEffects.clearFilter(); NosmaiEffects.clearAREffect(); NosmaiEffects.removeEffect(selected); NosmaiEffects.removeEffect();
iOS
[sdk clearFilter]; [sdk clearAREffect]; [sdk removeEffectInfo:selected]; [sdk removeAllFilters];
Use typed removal when the interface has one common Remove button for mixed package types.
Cloud packages
Cloud listing returns package metadata and preview information. The encrypted package is downloaded when the user selects it.
The flow is:
Get cloud list
|
v
Show metadata and preview
|
v
Download selected package
|
v
Receive local path
|
v
Call applyEffect(localPath)
Cloud type values
Cloud request values differ slightly from internal package types.
| Package type | Flutter cloud enum | API value |
|---|---|---|
filter | NosmaiCloudFilterType.filter | filter |
effect | NosmaiCloudFilterType.effects | effects |
beauty_effect | NosmaiCloudFilterType.beautyEffect | beauty_effect |
background | NosmaiCloudFilterType.background | bg |
Use the enum instead of typing these strings in Flutter.
Flutter cloud listing
Get all available cloud packages:
final packages =
await NosmaiFlutter.instance.getCloudFilters();
Get the first page of beauty effects:
final beautyEffects =
await NosmaiFlutter.instance.getCloudFilters(
filterType:
NosmaiCloudFilterType.beautyEffect,
page: 1,
limit: 20,
);
Cloud compatibility version 2 is selected automatically. The application does not need to pass a version for the normal request.
Read pagination:
final pagination =
NosmaiFlutter.instance.lastPaginationInfo;
if (pagination?.hasNextPage == true) {
final nextPage =
await NosmaiFlutter.instance.getCloudFilters(
filterType:
NosmaiCloudFilterType.beautyEffect,
page: pagination!.currentPage + 1,
limit: 20,
);
}
Download and apply in Flutter
final result =
await NosmaiFlutter.instance
.downloadCloudFilter(selected.cloudIdentifier);
if (result['success'] == true) {
final localPath =
result['localPath'] as String;
final applied =
await NosmaiFlutter.instance
.applyEffect(localPath);
}
Do not pass a cloud preview URL to applyEffect. Apply the downloaded local package path.
Recommended filter interface
Use separate tabs or sections:
Filters Effects Beauty Backgrounds
Map them as:
| Interface label | Package type |
|---|---|
| Filters | filter |
| Effects | effect |
| Beauty | beauty_effect |
| Backgrounds | background |
For each item, show:
- preview image
- display name
- download state for cloud items
- download progress when needed
- applying state
- selected state from the SDK
- a retry action after a temporary failure
Do not show internal paths, package headers, or decryption details to the user.
Apply-state handling
Use these interface states:
idle downloading applying selected failed
Recommended behavior:
- Disable repeated taps while one cloud download is active.
- Show download progress.
- Call
applyEffectafter the local path is available. - Mark the package selected only after success.
- Confirm the final selected state from the SDK.
- Restore the previous selected item if apply fails.
Do not call clear and apply together to replace a package. Apply the new package and let its type perform the correct replacement.
Face and background requirements
The application does not need to manually start face tracking for a package.
Nosmai reads the package requirements when it is applied. Depending on the package, the SDK can enable:
- face tracking
- face landmarks
- animation timing
- background subject detection
- background coexistence behavior
These behaviors depend on correct package metadata created by the filter author.
Performance guidance
For a smooth camera:
- keep package textures reasonably sized
- avoid repeated apply calls for the already selected item
- wait for an apply result before starting another expensive operation
- use production listing instead of debug discovery in a released app
- download cloud files before applying them
- avoid showing several animated previews at full resolution
- test face effects with rapid head movement
- test background packages on the lowest supported device
- test filters during recording and streaming
- test a long session for heat and memory use
A color filter is usually cheaper than a tracked effect, beauty_effect, or subject-aware background.
Error handling
Package apply can fail because:
- Nosmai is not initialized
- the path is empty
- the local file does not exist
- the package is incomplete
- the package cannot be decrypted
- the internal manifest is invalid
- the package type is invalid
- a required visual resource cannot be created
- the device does not support the required operation
- the license does not include the required feature
Keep technical details in logs. Show a short message such as:
This effect could not be applied. Please try again.
Do not change selected UI before success.
Summary
Use these rules:
filterchanges the overall frame appearance.effectprovides AR, tracking, animation, or interactive visuals.beauty_effectis a packaged beauty or makeup look.backgroundcontrols the area behind the subject.effectandbeauty_effectreplace each other.- Different package types can normally remain active together.
- Use
applyEffect(path)for every.nosmaipackage. - Use production methods for released applications.
- Use debug discovery only during development.
- Download cloud packages before applying their local path.
- Build selected UI from the SDK active state.
- Remove listeners when their screen closes.