Affinity Targeting

Affinities are weighted preferences that tell the matching engine what your brand looks and feels like. Each campaign can define up to 50 affinities across 8 types. Affinities serve two purposes: they influence the match scoring (making your campaign more likely to win relevant scenes) and they drive visual pipeline bias (changing how the scene actually looks when your campaign wins).

Affinity Types at a Glance

Type Match Method Visual Impact Scoring Impact
action Substring in narrative text None (scoring only) Weight added to affinity_match
location Same compatibility group Swaps scene location Weight added to affinity_match
theme Exact match with theme_id None (scoring only) Weight added to affinity_match
mood Exact match in mood_tags Indirect (influences lighting if no lighting affinity) Weight added to affinity_match
category Exact match with game category None (scoring only) 1.5x category_affinity multiplier
lighting Always matches (visual-only) Replaces scene lighting preset Weight added to affinity_match
effects Always matches (visual-only) Replaces scene effects preset Weight added to affinity_match
camera Reserved Reserved for future use Not yet scored

Weights

Each affinity has a weight field ranging from 0.1 to 3.0. The weight determines how much this affinity contributes to the campaign's match score when it matches the scene context.

Weight Range Meaning Use Case
0.1 - 0.5 Nice to have Slight preference, low-priority aesthetic
0.5 - 1.0 Moderate preference Standard targeting weight
1.0 - 2.0 Strong preference Core brand aesthetic, key theme alignment
2.0 - 3.0 Critical Brand-defining visual identity, must-have context

The affinity_match component of the scoring formula is: 1.0 + (sum of matched weights / total affinities). Higher weights on matching affinities directly increase your campaign's score.

action

Matches against the narrative text of the current scene using substring search. The affinity_value is searched as a case-insensitive substring within game_context.narrative.

Example values: "confrontation", "obtaining", "celebration", "negotiation", "crisis"

POST /api/ads/campaigns/{id}/affinities
{
  "affinity_type": "action",
  "affinity_value": "celebration",
  "weight": 1.5
}

This affinity matches if the narrative text contains the word "celebration" anywhere. Useful for brands that want to appear during specific narrative beats -- for example, a luxury brand targeting celebration scenes, or a security company targeting crisis moments.

location

Matches when the campaign's target location is in the same compatibility group as the scene's current location. If the campaign wins, the scene location is swapped to the affinity's location value -- but only if both locations belong to the same group. This preserves narrative coherence.

POST /api/ads/campaigns/{id}/affinities
{
  "affinity_type": "location",
  "affinity_value": "rooftop terrace",
  "weight": 1.0
}

In this example, if the base scene is set in "city plaza" (urban group), the affinity matches because "rooftop terrace" is also in the urban group. The scene location would be swapped to "rooftop terrace". However, if the base scene were "military bunker" (military group), this affinity would not match -- the groups are different.

Location Compatibility Groups

outdoor_nature

  • vast open landscape
  • mountaintop overlook
  • beach
  • tropical resort
  • forest clearing
  • desert expanse
  • lakeside

indoor_formal

  • library or study
  • boardroom
  • oval office
  • press briefing room
  • courtroom
  • embassy reception
  • war room

urban

  • modern urban street
  • marketplace or vault
  • futuristic cityscape
  • rooftop terrace
  • city plaza
  • subway station
  • neon-lit alley

liminal

  • crossroads or threshold
  • foggy street
  • dimly lit basement
  • abandoned building
  • tunnel entrance
  • deserted highway

military

  • military bunker
  • aircraft carrier deck
  • control room
  • pentagon corridor
  • missile silo
  • situation room

theme

Matches via exact match against game_context.theme_id. This is purely a scoring affinity -- it does not alter any visual pipeline slot.

POST /api/ads/campaigns/{id}/affinities
{
  "affinity_type": "theme",
  "affinity_value": "2",
  "weight": 2.0
}

Theme IDs correspond to the game's theme system (e.g., "1" = Watergate Redux, "2" = Pandemic Crisis, "4" = Corporate Takeover). A pharmaceutical company might weight the Pandemic Crisis theme highly, while a tech brand might target Corporate Takeover.

mood

Matches via exact match against the game_context.mood_tags list. If the scene's mood tags include the affinity value, the affinity matches.

POST /api/ads/campaigns/{id}/affinities
{
  "affinity_type": "mood",
  "affinity_value": "triumphant",
  "weight": 1.5
}

Common mood values:

  • "tense", "kinetic"
  • "bittersweet", "determined"
  • "reflective", "weary"
  • "contemplative", "eureka"
  • "triumphant", "jubilant"
  • "paranoid", "bitter"
  • "wonder", "possibility"
  • "solemn", "noble"

Mood affinities also have an indirect visual effect: if a campaign wins and has mood affinities but no explicit lighting affinity, the mood can influence the lighting choice in the biased pipeline.

category

Matches via exact match against the game's category. This affinity is unique because it triggers the category_affinity multiplier in the scoring formula (1.5x) rather than contributing to the affinity_match sum.

POST /api/ads/campaigns/{id}/affinities
{
  "affinity_type": "category",
  "affinity_value": "simulation",
  "weight": 1.0
}

When this affinity matches, the entire campaign score is multiplied by 1.5x. This makes category targeting one of the most impactful affinities for winning auctions. Common category values: "simulation", "rpg", "strategy", "adventure", "puzzle".

lighting

Controls the scene's lighting when the campaign wins. The affinity_value is a preset key that maps to a descriptive lighting string used by the game's rendering pipeline.

Preset Key Rendered As
warm warm golden hour
cool cool moonlight
dramatic dramatic silhouette
natural soft natural daylight
neon neon-lit urban glow
clinical sterile fluorescent
overcast overcast diffused
POST /api/ads/campaigns/{id}/affinities
{
  "affinity_type": "lighting",
  "affinity_value": "warm",
  "weight": 2.0
}

When this campaign wins, the biased_pipeline.lighting field in the match response will contain "warm golden hour", regardless of what the base scene's lighting was. This is a direct override -- the lighting affinity always applies when the campaign wins.

effects

Controls the scene's visual effects when the campaign wins. Like lighting, this is a direct override via preset keys.

Preset Key Rendered As
cinematic cinematic widescreen, film grain, shallow depth of field
vintage vintage film grain, muted tones, light leak
clean clean and modern, sharp focus, high contrast
dreamy soft focus, ethereal glow, pastel tones
noir high contrast, desaturated, heavy shadows
documentary handheld feel, naturalistic, sharp focus
epic sweeping scale, volumetric lighting, lens flare
POST /api/ads/campaigns/{id}/affinities
{
  "affinity_type": "effects",
  "affinity_value": "cinematic",
  "weight": 1.5
}

When this campaign wins, biased_pipeline.effects will be "cinematic widescreen, film grain, shallow depth of field".

camera

Reserved for future use. This affinity type is defined in the schema but is not yet scored or applied to the visual pipeline. It will eventually control camera angles such as close-up, wide angle, dutch angle, tracking shot, etc.

Bulk API

You can set multiple affinities at once using the bulk endpoint. This replaces all existing affinities for the campaign.

POST /api/ads/campaigns/{id}/affinities/bulk
Authorization: Bearer sk_live_xxx
Content-Type: application/json

{
  "affinities": [
    { "affinity_type": "lighting",  "affinity_value": "warm",         "weight": 2.0 },
    { "affinity_type": "effects",   "affinity_value": "cinematic",    "weight": 1.5 },
    { "affinity_type": "location",  "affinity_value": "rooftop terrace", "weight": 1.0 },
    { "affinity_type": "mood",      "affinity_value": "triumphant",   "weight": 1.0 },
    { "affinity_type": "action",    "affinity_value": "celebration",  "weight": 1.5 },
    { "affinity_type": "category",  "affinity_value": "simulation",   "weight": 1.0 },
    { "affinity_type": "theme",     "affinity_value": "4",            "weight": 2.0 }
  ]
}

Response:

{
  "campaign_id": "camp_abc123",
  "affinities_count": 7,
  "affinities": [
    { "id": "aff_001", "affinity_type": "lighting",  "affinity_value": "warm",         "weight": 2.0 },
    { "id": "aff_002", "affinity_type": "effects",   "affinity_value": "cinematic",    "weight": 1.5 },
    { "id": "aff_003", "affinity_type": "location",  "affinity_value": "rooftop terrace", "weight": 1.0 },
    { "id": "aff_004", "affinity_type": "mood",      "affinity_value": "triumphant",   "weight": 1.0 },
    { "id": "aff_005", "affinity_type": "action",    "affinity_value": "celebration",  "weight": 1.5 },
    { "id": "aff_006", "affinity_type": "category",  "affinity_value": "simulation",   "weight": 1.0 },
    { "id": "aff_007", "affinity_type": "theme",     "affinity_value": "4",            "weight": 2.0 }
  ]
}

Example: Brand Profiles

Luxury Watch Brand

{
  "affinities": [
    { "affinity_type": "lighting",  "affinity_value": "warm",      "weight": 2.5 },
    { "affinity_type": "effects",   "affinity_value": "cinematic", "weight": 2.0 },
    { "affinity_type": "location",  "affinity_value": "rooftop terrace", "weight": 1.5 },
    { "affinity_type": "mood",      "affinity_value": "triumphant", "weight": 1.5 },
    { "affinity_type": "action",    "affinity_value": "celebration", "weight": 1.0 }
  ]
}

Cyberpunk Game Studio

{
  "affinities": [
    { "affinity_type": "lighting",  "affinity_value": "neon",       "weight": 3.0 },
    { "affinity_type": "effects",   "affinity_value": "noir",       "weight": 2.0 },
    { "affinity_type": "location",  "affinity_value": "neon-lit alley", "weight": 2.0 },
    { "affinity_type": "mood",      "affinity_value": "paranoid",   "weight": 1.5 },
    { "affinity_type": "action",    "affinity_value": "confrontation", "weight": 1.0 }
  ]
}

Documentary Streaming Service

{
  "affinities": [
    { "affinity_type": "lighting",  "affinity_value": "natural",      "weight": 2.0 },
    { "affinity_type": "effects",   "affinity_value": "documentary",  "weight": 2.5 },
    { "affinity_type": "mood",      "affinity_value": "contemplative", "weight": 1.5 },
    { "affinity_type": "action",    "affinity_value": "revelation",   "weight": 2.0 },
    { "affinity_type": "category",  "affinity_value": "simulation",   "weight": 1.0 }
  ]
}

Related