Nosmai / docs
Nosmai Effects Nosmai Moderation Nosmai Try-ons coming soon
Docs menu Filters and effects
docs / nosmai effects / core concepts / filters and effects

Filters and effects

The difference between filters and effects, the .nosmai format, local versus cloud filters, and the built-in beauty and color controls.

Overview

Nosmai supports visual content through encrypted .nosmai packages. Every package declares one of four types:

  • filter
  • effect
  • beauty_effect
  • background

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 effect or beauty_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 effect replaces the current beauty_effect
  • applying a beauty_effect replaces the current effect

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 .nosmai file

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 effectBuilt-in beauty
Stored in a .nosmai packageCompiled into the SDK
Listed with local or cloud packagesControlled through direct methods
Applied with applyEffect(path)Applied with methods such as applySkinSmoothing or applyLipstick
Has package metadata and previewUses application-defined controls
Occupies the same position as an effectManaged 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 packageManual background
Distributed as a .nosmai fileCreated by the application
Listed as type backgroundNot part of the package catalog
Applied with applyEffect(path)Applied with background configuration methods
Contains authored package settingsUses 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

TypeMain purposeUsually tracks a faceReplacement rule
filterFull-frame color or visual styleNoReplaces the previous filter
effectAR, tracked, animated, or interactive effectOftenReplaces the current effect or beauty_effect
beauty_effectPackaged makeup or beauty lookYesReplaces the current effect or beauty_effect
backgroundPackaged background visualNo, but may identify the subjectReplaces the previous background

What can be active together

The package type controls replacement.

Active combinationResult
filter and effectBoth can remain active
filter and beauty_effectBoth can remain active
filter and backgroundBoth can remain active
beauty_effect and backgroundBoth can remain active
effect and beauty_effectThe latest package replaces the previous one
built-in beauty, makeup, reshape, color, or hair and effectThe latest mode clears the other mode
built-in beauty, makeup, reshape, color, or hair and beauty_effectThe latest mode clears the other mode
built-in controls and a regular external filterBoth can remain active
two filter packagesThe latest filter replaces the previous filter
two background packagesThe 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:

  • filter
  • effect
  • beauty_effect
  • background

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:

  1. subscribe to active-state changes
  2. read the current state once
  3. build selected UI from that state
  4. update the UI after future state changes
  5. 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 typeFlutter cloud enumAPI value
filterNosmaiCloudFilterType.filterfilter
effectNosmaiCloudFilterType.effectseffects
beauty_effectNosmaiCloudFilterType.beautyEffectbeauty_effect
backgroundNosmaiCloudFilterType.backgroundbg

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.

Use separate tabs or sections:

Filters
Effects
Beauty
Backgrounds

Map them as:

Interface labelPackage type
Filtersfilter
Effectseffect
Beautybeauty_effect
Backgroundsbackground

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:

  1. Disable repeated taps while one cloud download is active.
  2. Show download progress.
  3. Call applyEffect after the local path is available.
  4. Mark the package selected only after success.
  5. Confirm the final selected state from the SDK.
  6. 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:

  1. filter changes the overall frame appearance.
  2. effect provides AR, tracking, animation, or interactive visuals.
  3. beauty_effect is a packaged beauty or makeup look.
  4. background controls the area behind the subject.
  5. effect and beauty_effect replace each other.
  6. Different package types can normally remain active together.
  7. Use applyEffect(path) for every .nosmai package.
  8. Use production methods for released applications.
  9. Use debug discovery only during development.
  10. Download cloud packages before applying their local path.
  11. Build selected UI from the SDK active state.
  12. Remove listeners when their screen closes.
Nosmai

We make advanced camera and AI technology accessible to every developer. By packaging hard problems into simple

developers
legal
newsletter

Product updates and release notes. No spam.

© 2026 nosmai, inc · all rights reserved