Recommendation model

How LayerLab finds fragrance layers.

The current engine is rule-based and explainable. It compares two fragrances as weighted accord profiles, rewards useful harmony and contrast, then subtracts risk when a blend is likely to become too dense, too sweet, or overpowering.

01

Each fragrance becomes an accord vector

A fragrance is represented as accord strengths from 0 to 1. For example, a scent can be 0.90 fresh, 0.82 citrus, 0.78 aromatic, 0.62 spicy, and 0.54 amber.

This lets the app compare fragrances mathematically without pretending that perfume is fully objective. The numbers are a structured approximation of the scent profile.

02

Harmony pairs add score

Harmony rules reward accord combinations that are known to work well together, such as rose with oud, citrus with woods, vanilla with tobacco, musk with florals, amber with spices, and green notes with white florals.

harmony_score = pair_strength * 28

Pair strength uses the weaker side of the match, because a pairing only matters if both sides are actually present.

03

Contrast pairs add score

Contrast rules reward combinations that improve balance: fresh over amber, green over gourmand, citrus over smoke, musk with spice, vanilla with leather, and aquatic notes with woods.

These matches are not about similarity. They are about changing the first fragrance in a useful direction.

04

Bridge accords add stability

Some accords act like connectors between perfumes. The app currently treats musk, woods, amber, citrus, and powdery facets as bridge accords.

bridge_score = shared_bridge_strength * 10

If both fragrances share one of these bridge materials, the blend is more likely to feel intentional instead of like two separate perfumes fighting each other.

05

The user's goal changes the ranking

When the user chooses a goal, the partner fragrance receives extra score for accords that support that goal.

  • Fresher: fresh, citrus, green, aquatic, aromatic
  • Warmer: amber, vanilla, spicy, woody, resinous
  • Sweeter: sweet, vanilla, gourmand, fruity
  • Cleaner: musky, fresh, powdery, citrus
  • Darker: smoky, leather, oud, tobacco, resinous
  • More floral: floral, white floral, rose
  • Longer lasting: musky, amber, woody, vanilla, resinous
goal_score = matching_goal_accord_strength * 16
06

Risk penalties reduce score

The engine calculates density from heavy base accords: amber, vanilla, gourmand, smoky, leather, oud, tobacco, and resinous. It also calculates sweetness from sweet, vanilla, gourmand, and fruity accords.

  • Very dense blends lose 24 points.
  • Very sweet blends lose 18 points.
  • Two dense fragrances together lose another 12 points.

The final score

layer_score = harmony + contrast + bridge + goal - clash_penalty - overpower_penalty

The final score is clamped between 0 and 100, then recommendations below 25 are removed. The app shows the top scoring matches.

How spray order is chosen

Order depends on the desired effect. To brighten, clean up, or floralize a scent, the denser perfume usually goes first and the lighter modifier goes second. To warm, darken, or improve longevity, the lighter scent usually goes first and the denser base goes second.

If the user chooses a balanced match, the denser fragrance normally becomes the anchor and is sprayed first.

How spray ratio is chosen

The app compares density. If both fragrances have similar density, it recommends 1 spray plus 1 spray. If one is clearly heavier, it recommends fewer sprays of the denser scent and more room for the lighter scent.

Dense blends also get risk warnings that suggest fewer sprays or separate pulse points.

This is an explainable MVP model, not a machine-learning model. It is designed to be adjusted as the catalog grows and user ratings show which combinations work on real skin.